sp-js-provisioning
Version:
SharePoint provisioning with pure JavaScript
925 lines (924 loc) • 58.4 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
import initSpfxJsom from 'spfx-jsom';
import * as xmljs from 'xml-js';
import { addFieldAttributes } from '../util';
import { TokenHelper } from '../util/tokenhelper';
import { HandlerBase } from './handlerbase';
/**
* Describes the Lists Object Handler
*/
var Lists = /** @class */ (function (_super) {
__extends(Lists, _super);
/**
* Creates a new instance of the Lists class
*
* @param config - Provisioning config
*/
function Lists(config) {
return _super.call(this, 'Lists', config) || this;
}
/**
* Provisioning lists
*
* @param web - The web
* @param lists - The lists to provision
*/
Lists.prototype.ProvisionObjects = function (web, lists, context) {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c, error_1;
var _this = this;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_a = this;
return [4 /*yield*/, initSpfxJsom(context.web.ServerRelativeUrl)];
case 1:
_a.jsomContext = (_d.sent()).jsomContext;
this.context = context;
this.tokenHelper = new TokenHelper(this.context, this.config);
_super.prototype.scope_started.call(this);
_d.label = 2;
case 2:
_d.trys.push([2, 11, , 12]);
_b = this.context;
return [4 /*yield*/, web.lists.select('Id', 'Title')()];
case 3:
_b.lists = (_d.sent()).reduce(function (object, l) {
object[l.Title] = l.Id;
return object;
}, {});
return [4 /*yield*/, lists.reduce(function (chain, list) { return chain.then(function () { return _this.processList(web, list); }); }, Promise.resolve())];
case 4:
_d.sent();
return [4 /*yield*/, lists.reduce(function (chain, list) {
return chain.then(function () { return _this.processListFields(web, list); });
}, Promise.resolve())];
case 5:
_d.sent();
return [4 /*yield*/, lists.reduce(function (chain, list) {
return chain.then(function () { return _this.processListFieldRefs(web, list); });
}, Promise.resolve())];
case 6:
_d.sent();
return [4 /*yield*/, lists.reduce(function (chain, list) {
return chain.then(function () { return _this.processListViews(web, list); });
}, Promise.resolve())];
case 7:
_d.sent();
return [4 /*yield*/, lists.reduce(function (chain, list) {
return chain.then(function () { return _this.processListFolders(web, list); });
}, Promise.resolve())];
case 8:
_d.sent();
return [4 /*yield*/, lists.reduce(function (chain, list) {
return chain.then(function () { return _this.processListDataRows(web, list); });
}, Promise.resolve())];
case 9:
_d.sent();
_c = this.context;
return [4 /*yield*/, web.lists.select('Id', 'Title')()];
case 10:
_c.lists = (_d.sent()).reduce(function (object, l) {
object[l.Title] = l.Id;
return object;
}, {});
_super.prototype.scope_ended.call(this);
return [3 /*break*/, 12];
case 11:
error_1 = _d.sent();
_super.prototype.scope_ended.call(this, error_1);
throw error_1;
case 12: return [2 /*return*/];
}
});
});
};
/**
* Processes a list
*
* @param web - The web
* @param lc - The list
*/
Lists.prototype.processList = function (web, lc) {
return __awaiter(this, void 0, void 0, function () {
var list, listEnsure, listAdd;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_super.prototype.log_info.call(this, 'processList', "Processing list " + lc.Title);
if (!this.context.lists[lc.Title]) return [3 /*break*/, 2];
_super.prototype.log_info.call(this, 'processList', "List " + lc.Title + " already exists. Ensuring...");
return [4 /*yield*/, web.lists.ensure(lc.Title, lc.Description, lc.Template, lc.ContentTypesEnabled, lc.AdditionalSettings)];
case 1:
listEnsure = _a.sent();
list = listEnsure.list;
return [3 /*break*/, 4];
case 2:
_super.prototype.log_info.call(this, 'processList', "List " + lc.Title + " doesn't exist. Creating...");
return [4 /*yield*/, web.lists.add(lc.Title, lc.Description, lc.Template, lc.ContentTypesEnabled, lc.AdditionalSettings)];
case 3:
listAdd = _a.sent();
list = listAdd.list;
this.context.lists[listAdd.data.Title] = listAdd.data.Id;
_a.label = 4;
case 4:
if (!lc.ContentTypeBindings) return [3 /*break*/, 6];
return [4 /*yield*/, this.processContentTypeBindings(lc, list, lc.ContentTypeBindings, lc.RemoveExistingContentTypes)];
case 5:
_a.sent();
_a.label = 6;
case 6: return [2 /*return*/];
}
});
});
};
/**
* Processes content type bindings for a list
*
* @param lc - The list configuration
* @param list - The pnp list
* @param contentTypeBindings - Content type bindings
* @param removeExisting - Remove existing content type bindings
*/
Lists.prototype.processContentTypeBindings = function (lc, list, contentTypeBindings, removeExisting) {
return __awaiter(this, void 0, void 0, function () {
var promises_1, contentTypes;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_super.prototype.log_info.call(this, 'processContentTypeBindings', "Processing content types for list " + lc.Title + ".");
return [4 /*yield*/, contentTypeBindings.reduce(function (chain, ct) {
return chain.then(function () {
return _this.processContentTypeBinding(lc, list, ct.ContentTypeID);
});
}, Promise.resolve())];
case 1:
_a.sent();
if (!removeExisting) return [3 /*break*/, 4];
promises_1 = [];
return [4 /*yield*/, list.contentTypes()];
case 2:
contentTypes = _a.sent();
contentTypes.forEach(function (_a) {
var ContentTypeId = _a.Id.StringValue;
var shouldRemove = contentTypeBindings.filter(function (ctb) {
return ContentTypeId.includes(ctb.ContentTypeID);
}).length === 0 && !ContentTypeId.includes('0x0120');
if (shouldRemove) {
_super.prototype.log_info.call(_this, 'processContentTypeBindings', "Removing content type " + ContentTypeId + " from list " + lc.Title);
// A content type that is still in use by existing items can't be
// removed (SharePoint returns 500 "content type still in use"). Don't
// let that abort the whole provisioning — log it and carry on.
promises_1.push(list.contentTypes
.getById(ContentTypeId)
.delete()
.catch(function (error) {
return _super.prototype.log_info.call(_this, 'processContentTypeBindings', "Failed to remove content type " + ContentTypeId + " from list " + lc.Title + " (likely still in use): " + ((error && error.message) || error));
}));
}
else {
_super.prototype.log_info.call(_this, 'processContentTypeBindings', "Skipping removal of content type " + ContentTypeId + " from list " + lc.Title);
}
});
return [4 /*yield*/, Promise.all(promises_1)];
case 3:
_a.sent();
_a.label = 4;
case 4: return [2 /*return*/];
}
});
});
};
/**
* Processes a content type binding for a list
*
* @param lc - The list configuration
* @param list - The pnp list
* @param contentTypeID - The Content Type ID
*/
Lists.prototype.processContentTypeBinding = function (lc, list, contentTypeID) {
return __awaiter(this, void 0, void 0, function () {
var existing, alreadyBound, error_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
return [4 /*yield*/, list.contentTypes()];
case 1:
existing = _a.sent();
alreadyBound = (existing || []).some(function (ct) { return ("" + (ct && ct.Id && ct.Id.StringValue)).indexOf(contentTypeID) === 0; });
if (alreadyBound) {
_super.prototype.log_info.call(this, 'processContentTypeBinding', "Content Type " + contentTypeID + " already bound to list " + lc.Title + " \u2014 skipping.");
return [2 /*return*/];
}
_super.prototype.log_info.call(this, 'processContentTypeBinding', "Adding content Type " + contentTypeID + " to list " + lc.Title + ".");
return [4 /*yield*/, list.contentTypes.addAvailableContentType(contentTypeID)];
case 2:
_a.sent();
_super.prototype.log_info.call(this, 'processContentTypeBinding', "Content Type " + contentTypeID + " added successfully to list " + lc.Title + ".");
return [3 /*break*/, 4];
case 3:
error_2 = _a.sent();
_super.prototype.log_info.call(this, 'processContentTypeBinding', "Failed to add Content Type " + contentTypeID + " to list " + lc.Title + ": " + ((error_2 && error_2.message) || error_2));
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
/**
* Processes fields for a list
*
* @param web - The web
* @param list - The pnp list
*/
Lists.prototype.processListFields = function (web, list) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!list.Fields) return [3 /*break*/, 2];
return [4 /*yield*/, list.Fields.reduce(function (chain, field) { return chain.then(function () { return _this.processField(web, list, field); }); }, Promise.resolve())];
case 1:
_a.sent();
_a.label = 2;
case 2: return [2 /*return*/];
}
});
});
};
/**
* Processes a field for a lit
*
* @param web - The web
* @param lc - The list configuration
* @param fieldXml - Field XML
*/
Lists.prototype.processField = function (web, lc, fieldXml) {
return __awaiter(this, void 0, void 0, function () {
var list, fieldXmlJson, fieldAttribute, fieldName, fieldDisplayName, _a, fieldAddResult, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
list = web.lists.getByTitle(lc.Title);
fieldXmlJson = JSON.parse(xmljs.xml2json(fieldXml));
fieldAttribute = fieldXmlJson.elements[0].attributes;
fieldName = fieldAttribute.Name;
fieldDisplayName = fieldAttribute.DisplayName;
_super.prototype.log_info.call(this, 'processField', "Processing field " + fieldName + " (" + fieldDisplayName + ") for list " + lc.Title + ".");
fieldXmlJson.elements[0].attributes.DisplayName = fieldName;
fieldXml = xmljs.json2xml(fieldXmlJson);
_c.label = 1;
case 1:
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, list.fields.getById(fieldAttribute.ID).delete()];
case 2:
_c.sent();
_super.prototype.log_info.call(this, 'processField', "Field " + fieldName + " (" + fieldDisplayName + ") successfully deleted from list " + lc.Title + ".");
return [3 /*break*/, 4];
case 3:
_a = _c.sent();
_super.prototype.log_info.call(this, 'processField', "Field " + fieldName + " (" + fieldDisplayName + ") does not exist in list " + lc.Title + ".");
return [3 /*break*/, 4];
case 4:
_c.trys.push([4, 7, , 8]);
return [4 /*yield*/, list.fields.createFieldAsXml(this.tokenHelper.replaceTokens(fieldXml))];
case 5:
fieldAddResult = _c.sent();
return [4 /*yield*/, fieldAddResult.field.update({ Title: fieldDisplayName })];
case 6:
_c.sent();
_super.prototype.log_info.call(this, 'processField', "Field '" + fieldDisplayName + "' added successfully to list " + lc.Title + ".");
return [3 /*break*/, 8];
case 7:
_b = _c.sent();
_super.prototype.log_info.call(this, 'processField', "Failed to add field '" + fieldDisplayName + "' to list " + lc.Title + ".");
return [3 /*break*/, 8];
case 8: return [2 /*return*/];
}
});
});
};
/**
* Processes field refs for a list
*
* @param web - The web
* @param lc - The list configuration
*/
Lists.prototype.processListFieldRefs = function (web, lc) {
return __awaiter(this, void 0, void 0, function () {
var list_1, _a, listFields_1, webFields_1;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!lc.FieldRefs) return [3 /*break*/, 4];
_super.prototype.log_info.call(this, 'processListFieldRefs', "Retrieving fields for list " + lc.Title + " and web.");
list_1 = web.lists.getByTitle(lc.Title);
return [4 /*yield*/, Promise.all([
list_1.fields.select('Id', 'InternalName', 'SchemaXml')(),
web.fields.select('Id', 'InternalName', 'SchemaXml')()
])];
case 1:
_a = __read.apply(void 0, [_b.sent(), 2]), listFields_1 = _a[0], webFields_1 = _a[1];
_super.prototype.log_info.call(this, 'processListFieldRefs', "Fields for list " + lc.Title + " and web retrieved. Processing field refs.");
return [4 /*yield*/, lc.FieldRefs.reduce(function (chain, fieldReference) {
return chain.then(function () {
return _this.processFieldRef(list_1, lc, fieldReference, listFields_1, webFields_1);
});
}, Promise.resolve())];
case 2: return [4 /*yield*/, _b.sent()];
case 3:
_b.sent();
_b.label = 4;
case 4: return [2 /*return*/];
}
});
});
};
/**
*
* Processes a field ref for a list
*
* @param list - The list
* @param lc - The list configuration
* @param fieldRef - The list field ref
* @param listFields - The list fields
* @param webFields - The web fields
*/
Lists.prototype.processFieldRef = function (list, lc, fieldReference, listFields, webFields) {
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var listFld, webFld, schemaXml, schemaXml, fieldAddResult;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
listFld = listFields.find(function (f) { return f.Id === fieldReference.ID; });
webFld = webFields.find(function (f) { return f.Id === fieldReference.ID; });
_super.prototype.log_info.call(this, 'processFieldRef', "Processing field ref '" + fieldReference.ID + "' for list " + lc.Title + ".");
if (!Boolean(listFld)) return [3 /*break*/, 4];
return [4 /*yield*/, list.fields.getById(fieldReference.ID).update({
Hidden: fieldReference.Hidden,
Required: fieldReference.Required,
Title: fieldReference.DisplayName
})];
case 1:
_c.sent();
if (!fieldReference.AdditionalProperties) return [3 /*break*/, 3];
schemaXml = addFieldAttributes(listFld.SchemaXml, __assign({ Hidden: fieldReference.Hidden, Required: fieldReference.Required, DisplayName: fieldReference.Name }, ((_a = fieldReference.AdditionalProperties) !== null && _a !== void 0 ? _a : {})));
_super.prototype.log_info.call(this, 'processFieldRef', "Additional properties set for field ref '" + fieldReference.ID + "' for list " + lc.Title + ". Attempting to generate schema XML.", { schemaXml: schemaXml });
return [4 /*yield*/, list.fields
.getById(fieldReference.ID)
.update({ SchemaXml: schemaXml })];
case 2:
_c.sent();
_c.label = 3;
case 3:
_super.prototype.log_info.call(this, 'processFieldRef', "Field '" + fieldReference.ID + "' updated for list " + lc.Title + ".");
return [3 /*break*/, 7];
case 4:
if (!Boolean(webFld)) return [3 /*break*/, 7];
_super.prototype.log_info.call(this, 'processFieldRef', "Adding field '" + fieldReference.ID + "' to list " + lc.Title + ".");
schemaXml = addFieldAttributes(webFld.SchemaXml, __assign({ DisplayName: fieldReference.Name, SourceID: "{" + this.context.lists[lc.Title] + "}" }, ((_b = fieldReference.AdditionalProperties) !== null && _b !== void 0 ? _b : {})));
return [4 /*yield*/, list.fields.createFieldAsXml(schemaXml)];
case 5:
fieldAddResult = _c.sent();
return [4 /*yield*/, fieldAddResult.field.update({
Title: fieldReference.DisplayName,
Required: fieldReference.Required,
Hidden: fieldReference.Hidden
})];
case 6:
_c.sent();
_super.prototype.log_info.call(this, 'processFieldRef', "Field '" + fieldReference.ID + "' added from web.");
_c.label = 7;
case 7: return [2 /*return*/];
}
});
});
};
/**
* Processes views for a list
*
* @param web - The web
* @param lc - The list configuration
*/
Lists.prototype.processListViews = function (web, lc) {
return __awaiter(this, void 0, void 0, function () {
var _a;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!lc.Views) return [3 /*break*/, 4];
if (!lc.RemoveExistingViews) return [3 /*break*/, 2];
return [4 /*yield*/, this.removeExistingViews(web, lc)];
case 1:
_b.sent();
_b.label = 2;
case 2: return [4 /*yield*/, lc.Views.reduce(function (chain, view) { return chain.then(function () { return _this.processView(web, lc, view); }); }, Promise.resolve())];
case 3:
_b.sent();
_b.label = 4;
case 4:
_a = this.context;
return [4 /*yield*/, web.lists.getByTitle(lc.Title).views.select('Id', 'Title')()];
case 5:
_a.listViews = (_b.sent()).reduce(function (object, view) {
object[lc.Title + "|" + view.Title] = view.Id;
return object;
}, this.context.listViews);
return [2 /*return*/];
}
});
});
};
/**
* Removes existing views for a list
*
* @param web - The web
* @param lc - The list configuration
*/
Lists.prototype.removeExistingViews = function (web, lc) {
return __awaiter(this, void 0, void 0, function () {
var views, promises;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, web.lists
.getByTitle(lc.Title)
.views.select('Id', 'Title')()];
case 1:
views = _a.sent();
_super.prototype.log_info.call(this, '_removeExistingViews', "Removing existing views for list " + lc.Title + ".", views.map(function (view) { return view.Title; }));
promises = views.map(function (view) {
return web.lists.getByTitle(lc.Title).views.getById(view.Id).delete();
});
return [4 /*yield*/, Promise.all(promises)];
case 2:
_a.sent();
_super.prototype.log_info.call(this, '_removeExistingViews', "Existing views removed for list " + lc.Title + ".");
return [2 /*return*/];
}
});
});
};
/**
* Processes a view for a list
*
* @param web - The web
* @param lc - The list configuration
* @param lvc - The view configuration
*/
Lists.prototype.processView = function (web, lc, lvc) {
return __awaiter(this, void 0, void 0, function () {
var existingView, viewExists, _a, newView, error_3, error_4;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_super.prototype.log_info.call(this, 'processView', "Processing view " + lvc.Title + " for list " + lc.Title + ".");
existingView = web.lists
.getByTitle(lc.Title)
.views.getByTitle(lvc.Title);
viewExists = false;
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
return [4 /*yield*/, existingView()];
case 2:
_b.sent();
viewExists = true;
return [3 /*break*/, 4];
case 3:
_a = _b.sent();
return [3 /*break*/, 4];
case 4:
_b.trys.push([4, 15, , 16]);
if (!viewExists) return [3 /*break*/, 7];
_super.prototype.log_info.call(this, 'processView', "View " + lvc.Title + " for list " + lc.Title + " already exists, updating.");
return [4 /*yield*/, existingView.update(lvc.AdditionalSettings)];
case 5:
_b.sent();
_super.prototype.log_info.call(this, 'processView', "View " + lvc.Title + " successfully updated for list " + lc.Title + ".");
return [4 /*yield*/, this.processViewFields(existingView, lvc)];
case 6:
_b.sent();
return [3 /*break*/, 14];
case 7:
_super.prototype.log_info.call(this, 'processView', "View " + lvc.Title + " for list " + lc.Title + " doesn't exists, creating.");
return [4 /*yield*/, web.lists
.getByTitle(lc.Title)
.views.add(lvc.Title, lvc.PersonalView, lvc.AdditionalSettings)
// SP REST's view-create endpoint silently ignores properties such as
// CustomFormatter, ViewType2 and Scope. Re-apply AdditionalSettings
// via update so newly created views match updated views. Re-resolve
// the view by title rather than reusing the IViewAddResult, since the
// returned reference is bound to the parent views collection and the
// update can silently no-op on some PnPjs/SharePoint combinations.
];
case 8:
_b.sent();
newView = web.lists
.getByTitle(lc.Title)
.views.getByTitle(lvc.Title);
_b.label = 9;
case 9:
_b.trys.push([9, 11, , 12]);
return [4 /*yield*/, newView.update(lvc.AdditionalSettings)];
case 10:
_b.sent();
return [3 /*break*/, 12];
case 11:
error_3 = _b.sent();
_super.prototype.log_warn.call(this, 'processView', "Failed to re-apply AdditionalSettings on newly created view " + lvc.Title + ": " + error_3);
return [3 /*break*/, 12];
case 12:
_super.prototype.log_info.call(this, 'processView', "View " + lvc.Title + " added successfully to list " + lc.Title + ".");
return [4 /*yield*/, this.processViewFields(newView, lvc)];
case 13:
_b.sent();
_b.label = 14;
case 14: return [3 /*break*/, 16];
case 15:
error_4 = _b.sent();
_super.prototype.log_error.call(this, 'processView', "Failed to process view " + lvc.Title + ": " + error_4);
return [3 /*break*/, 16];
case 16: return [2 /*return*/];
}
});
});
};
/**
* Processes view fields for a view
*
* @param view - The pnp view
* @param lvc - The view configuration
*/
Lists.prototype.processViewFields = function (view, lvc) {
return __awaiter(this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 3, , 4]);
_super.prototype.log_info.call(this, 'processViewFields', "Processing view fields for view " + lvc.Title + ".");
return [4 /*yield*/, view.fields.removeAll()];
case 1:
_b.sent();
return [4 /*yield*/, lvc.ViewFields.reduce(function (chain, viewField) { return chain.then(function () { return view.fields.add(viewField); }); }, Promise.resolve())];
case 2:
_b.sent();
_super.prototype.log_info.call(this, 'processViewFields', "View fields successfully processed for view " + lvc.Title + ".");
return [3 /*break*/, 4];
case 3:
_a = _b.sent();
_super.prototype.log_info.call(this, 'processViewFields', "Failed to process view fields for view " + lvc.Title + ".");
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
});
};
/**
* Provisions a folder hierarchy inside a list / document library. Runs after
* the list, its fields and views exist. Creation is idempotent: an existing
* folder is left in place and recursion continues into its children, so
* re-running the template is safe. A folder that fails to create is logged
* and skipped (along with its subtree) rather than aborting the whole list.
*
* @param web - The web
* @param lc - The list configuration
*/
Lists.prototype.processListFolders = function (web, lc) {
return __awaiter(this, void 0, void 0, function () {
var folders, list, rootServerRelativeUrl, rootInfo, error_5;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
folders = lc.Folders;
if (!folders || folders.length === 0)
return [2 /*return*/];
_super.prototype.log_info.call(this, 'processListFolders', "Provisioning " + folders.length + " top-level folder(s) for list " + lc.Title + ".");
list = web.lists.getByTitle(lc.Title);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, list.rootFolder.select('ServerRelativeUrl')()];
case 2:
rootInfo = _a.sent();
rootServerRelativeUrl = rootInfo.ServerRelativeUrl;
return [3 /*break*/, 4];
case 3:
error_5 = _a.sent();
_super.prototype.log_info.call(this, 'processListFolders', "Could not resolve root folder for list " + lc.Title + ": " + ((error_5 && error_5.message) || error_5));
return [2 /*return*/];
case 4: return [4 /*yield*/, this._processFolderLevel(list.rootFolder, rootServerRelativeUrl, folders, lc.Title)];
case 5:
_a.sent();
return [2 /*return*/];
}
});
});
};
/**
* Creates each folder in `folders` beneath `parentFolder` (idempotent) then
* recurses into its children. `parentServerRelativeUrl` is used only for
* logging the full path.
*
* @param parentFolder - The PnP parent folder
* @param parentServerRelativeUrl - Server-relative URL of the parent folder
* @param folders - Folder configs to create at this level
* @param listTitle - The list title (for logging)
*/
Lists.prototype._processFolderLevel = function (parentFolder, parentServerRelativeUrl, folders, listTitle) {
return __awaiter(this, void 0, void 0, function () {
var existingNames, existingFolders, _a, folders_1, folders_1_1, folder, name_1, childServerRelativeUrl, childFolder, error_6, e_1_1;
var e_1, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
existingNames = [];
_c.label = 1;
case 1:
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, parentFolder.folders.select('Name')()];
case 2:
existingFolders = _c.sent();
existingNames = (existingFolders || []).map(function (f) { return ("" + f.Name).toLowerCase(); });
return [3 /*break*/, 4];
case 3:
_a = _c.sent();
return [3 /*break*/, 4];
case 4:
_c.trys.push([4, 15, 16, 17]);
folders_1 = __values(folders), folders_1_1 = folders_1.next();
_c.label = 5;
case 5:
if (!!folders_1_1.done) return [3 /*break*/, 14];
folder = folders_1_1.value;
name_1 = folder.Name;
if (!name_1)
return [3 /*break*/, 13];
childServerRelativeUrl = parentServerRelativeUrl + "/" + name_1;
_c.label = 6;
case 6:
_c.trys.push([6, 12, , 13]);
childFolder = void 0;
if (!(existingNames.indexOf(("" + name_1).toLowerCase()) !== -1)) return [3 /*break*/, 7];
childFolder = parentFolder.folders.getByUrl(name_1);
_super.prototype.log_info.call(this, 'processListFolders', "Folder '" + childServerRelativeUrl + "' already exists in list " + listTitle + " \u2014 skipping creation.");
return [3 /*break*/, 9];
case 7: return [4 /*yield*/, parentFolder.addSubFolderUsingPath(name_1)];
case 8:
childFolder = _c.sent();
_super.prototype.log_info.call(this, 'processListFolders', "Created folder '" + childServerRelativeUrl + "' in list " + listTitle + ".");
_c.label = 9;
case 9:
if (!(folder.Folders && folder.Folders.length > 0)) return [3 /*break*/, 11];
return [4 /*yield*/, this._processFolderLevel(childFolder, childServerRelativeUrl, folder.Folders, listTitle)];
case 10:
_c.sent();
_c.label = 11;
case 11: return [3 /*break*/, 13];
case 12:
error_6 = _c.sent();
_super.prototype.log_info.call(this, 'processListFolders', "Failed to provision folder '" + childServerRelativeUrl + "' in list " + listTitle + ": " + ((error_6 && error_6.message) || error_6));
return [3 /*break*/, 13];
case 13:
folders_1_1 = folders_1.next();
return [3 /*break*/, 5];
case 14: return [3 /*break*/, 17];
case 15:
e_1_1 = _c.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 17];
case 16:
try {
if (folders_1_1 && !folders_1_1.done && (_b = folders_1.return)) _b.call(folders_1);
}
finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/];
case 17: return [2 /*return*/];
}
});
});
};
/**
* Provisions seed data rows for a list. Runs last (after fields, content
* types and views exist). Upserts by KeyColumn so re-running is idempotent,
* and resolves Lookup/User/Taxonomy values. A failing row is logged and
* skipped rather than aborting the whole list.
*
* @param web - The web
* @param lc - The list configuration
*/
Lists.prototype.processListDataRows = function (web, lc) {
return __awaiter(this, void 0, void 0, function () {
var dataRows, KeyColumn, _a, UpdateBehavior, Rows, list, fields, byName, byId, _b, _c, _d, index, row, values, existingId, keyValue, matches, error_7, e_2_1;
var e_2, _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
dataRows = lc.DataRows;
if (!dataRows || !dataRows.Rows || dataRows.Rows.length === 0)
return [2 /*return*/];
KeyColumn = dataRows.KeyColumn, _a = dataRows.UpdateBehavior, UpdateBehavior = _a === void 0 ? 'Overwrite' : _a, Rows = dataRows.Rows;
_super.prototype.log_info.call(this, 'processListDataRows', "Provisioning " + Rows.length + " data row(s) for list " + lc.Title + ".");
list = web.lists.getByTitle(lc.Title);
return [4 /*yield*/, list.fields.select('Id', 'InternalName', 'TypeAsString', 'LookupList', 'LookupField', 'TextField')()];
case 1:
fields = _f.sent();
byName = new Map(fields.map(function (f) { return [f.InternalName, f]; }));
byId = new Map(fields.map(function (f) { return [Lists._normGuid(f.Id), f]; }));
_f.label = 2;
case 2:
_f.trys.push([2, 15, 16, 17]);
_b = __values(Rows.entries()), _c = _b.next();
_f.label = 3;
case 3:
if (!!_c.done) return [3 /*break*/, 14];
_d = __read(_c.value, 2), index = _d[0], row = _d[1];
_f.label = 4;
case 4:
_f.trys.push([4, 12, , 13]);
return [4 /*yield*/, this._buildItemValues(web, byName, byId, row)];
case 5:
values = _f.sent();
existingId = void 0;
keyValue = KeyColumn ? row[KeyColumn] : undefined;
if (!(KeyColumn && keyValue !== undefined && keyValue !== null)) return [3 /*break*/, 7];
return [4 /*yield*/, list.items
.filter(KeyColumn + " eq '" + Lists._escapeOData(String(keyValue)) + "'")
.select('Id')
.top(1)()];
case 6:
matches = _f.sent();
existingId = matches[0] ? matches[0].Id : undefined;
_f.label = 7;
case 7:
if (!(existingId !== undefined)) return [3 /*break*/, 9];
if (UpdateBehavior === 'Skip') {
_super.prototype.log_info.call(this, 'processListDataRows', "Row " + index + " already exists (" + KeyColumn + "=" + keyValue + ") \u2014 skipped.");
return [3 /*break*/, 13];
}
return [4 /*yield*/, list.items.getById(existingId).update(values)];
case 8:
_f.sent();
return [3 /*break*/, 11];
case 9: return [4 /*yield*/, list.items.add(values)];
case 10:
_f.sent();
_f.label = 11;
case 11: return [3 /*break*/, 13];
case 12:
error_7 = _f.sent();
_super.prototype.log_info.call(this, 'processListDataRows', "Failed to provision row " + index + " in list " + lc.Title + ": " + ((error_7 && error_7.message) || error_7));
return [3 /*break*/, 13];
case 13:
_c = _b.next();
return [3 /*break*/, 3];
case 14: return [3 /*break*/, 17];
case 15:
e_2_1 = _f.sent();
e_2 = { error: e_2_1 };
return [3 /*break*/, 17];
case 16:
try {
if (_c && !_c.done && (_e = _b.return)) _e.call(_b);
}
finally { if (e_2) throw e_2.error; }
return [7 /*endfinally*/];
case 17: return [2 /*return*/];
}
});
});
};
/**
* Builds the REST item payload from a data row, mapping each field by type
* (Lookup/User → `<Field>Id`, Taxonomy → the hidden note field, URL, etc.).
*/
Lists.prototype._buildItemValues = function (web, byName, byId, row) {
return __awaiter(this, void 0, void 0, function () {
var values, _loop_1, this_1, _a, _b, fieldName, e_3_1;
var e_3, _c;
var _this = this;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
values = {};
_loop_1 = function (fieldName) {
var raw, def, type, _a, _b, _c, _d, _e, _f, _g, _h, _j;
return __generator(this, function (_k) {
switch (_k.label) {
case 0:
raw = row[fieldName];
if (raw === null || raw === undefined)
return [2 /*return*/, "continue"];
def = byName.get(fieldName);
type = (def && def.TypeAsString) || 'Text';
_a = type;
switch (_a) {
case 'Lookup': return [3 /*break*/, 1];
case 'LookupMulti': return [3 /*break*/, 3];
case 'User': return [3 /*break*/, 5];
case 'UserMulti': return [3 /*break*/, 7];
case 'TaxonomyFieldType': return [3 /*break*/, 9];
case 'TaxonomyFieldTypeMulti': return [3 /*break*/, 9];
case 'URL': return [3 /*break*/, 10];
case 'MultiChoice': return [3 /*break*/, 11];
case 'Boolean': return [3 /*break*/, 12];
case 'DateTime': return [3 /*break*/, 13];
}
return [3 /*break*/, 14];
case 1:
_b = values;
_c = fieldName + "Id";
return [4 /*yield*/, this_1._resolveLookupId(web, def, raw)];
case 2: