UNPKG

sp-js-provisioning

Version:
925 lines (924 loc) 58.4 kB
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: