automizer.jsā¢19.8 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const slide_1 = require("./classes/slide");
const template_1 = require("./classes/template");
const general_helper_1 = require("./helper/general-helper");
const master_1 = require("./classes/master");
const path_1 = __importDefault(require("path"));
const fs = __importStar(require("fs"));
const xml_helper_1 = require("./helper/xml-helper");
const modify_presentation_helper_1 = __importDefault(require("./helper/modify-presentation-helper"));
const content_tracker_1 = require("./helper/content-tracker");
/**
* Automizer
*
* The basic class for `pptx-automizer` package.
* This class will be exported as `Automizer` by `index.ts`.
*/
class Automizer {
/**
* Creates an instance of `pptx-automizer`.
* @param [params]
*/
constructor(params) {
var _a, _b, _c, _d;
/**
* Templates of automizer
* @internal
*/
this.templates = [];
this.modifyPresentation = [];
this.params = params;
this.templateDir = (params === null || params === void 0 ? void 0 : params.templateDir) ? params.templateDir + '/' : '';
this.templateFallbackDir = (params === null || params === void 0 ? void 0 : params.templateFallbackDir)
? params.templateFallbackDir + '/'
: '';
this.outputDir = (params === null || params === void 0 ? void 0 : params.outputDir) ? params.outputDir + '/' : '';
this.archiveParams = {
mode: ((_a = params === null || params === void 0 ? void 0 : params.archiveType) === null || _a === void 0 ? void 0 : _a.mode) || 'jszip',
baseDir: ((_b = params === null || params === void 0 ? void 0 : params.archiveType) === null || _b === void 0 ? void 0 : _b.baseDir) || __dirname + '/../cache',
workDir: ((_c = params === null || params === void 0 ? void 0 : params.archiveType) === null || _c === void 0 ? void 0 : _c.workDir) || 'tmp',
cleanupWorkDir: (_d = params === null || params === void 0 ? void 0 : params.archiveType) === null || _d === void 0 ? void 0 : _d.cleanupWorkDir,
};
this.timer = Date.now();
this.setStatusTracker(params === null || params === void 0 ? void 0 : params.statusTracker);
this.content = new content_tracker_1.ContentTracker();
if (params.rootTemplate) {
const location = this.getLocation(params.rootTemplate, 'template');
this.rootTemplate = template_1.Template.import(location, this.archiveParams, this);
}
if (params.presTemplates) {
this.params.presTemplates.forEach((file) => {
const location = this.getLocation(file, 'template');
const archiveParams = Object.assign(Object.assign({}, this.archiveParams), { name: file });
const newTemplate = template_1.Template.import(location, archiveParams);
this.templates.push(newTemplate);
});
}
}
setStatusTracker(statusTracker) {
const defaultStatusTracker = (status) => {
console.log(status.info + ' (' + status.share + '%)');
};
this.status = {
current: 0,
max: 0,
share: 0,
info: undefined,
increment: () => {
this.status.current++;
const nextShare = this.status.max > 0
? Math.round((this.status.current / this.status.max) * 100)
: 0;
if (this.status.share !== nextShare) {
this.status.share = nextShare;
this.status.next(this.status);
}
},
next: statusTracker || defaultStatusTracker,
};
}
/**
*/
presentation() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (((_a = this.params) === null || _a === void 0 ? void 0 : _a.useCreationIds) === true) {
yield this.setCreationIds();
}
return this;
});
}
/**
* Load a pptx file and set it as root template.
* @param location - Filename or path to the template. Will be prefixed with 'templateDir'
* @returns Instance of Automizer
*/
loadRoot(location) {
return this.loadTemplate(location);
}
/**
* Load a template pptx file.
* @param location - Filename or path to the template. Will be prefixed with 'templateDir'
* @param name - Optional: A short name for the template. If skipped, the template will be named by its location.
* @returns Instance of Automizer
*/
load(location, name) {
name = name === undefined ? location : name;
return this.loadTemplate(location, name);
}
/**
* Loads a pptx file either as a root template as a template file.
* A name can be specified to give templates an alias.
* @param location
* @param [name]
* @returns template
*/
loadTemplate(location, name) {
location = this.getLocation(location, 'template');
const alreadyLoaded = this.templates.find((template) => template.name === name);
if (alreadyLoaded) {
return this;
}
const importParams = Object.assign(Object.assign({}, this.archiveParams), { name });
const newTemplate = template_1.Template.import(location, importParams, this);
if (!this.isPresTemplate(newTemplate)) {
this.rootTemplate = newTemplate;
}
else {
this.templates.push(newTemplate);
}
return this;
}
/**
* Load media files to output presentation.
* @returns Instance of Automizer
* @param filename Filename or path to the media file.
* @param dir Specify custom path for media instead of mediaDir from AutomizerParams.
*/
loadMedia(filename, dir, prefix) {
const files = general_helper_1.GeneralHelper.arrayify(filename);
if (!this.rootTemplate) {
throw "Can't load media, you need to load a root template first";
}
files.forEach((file) => {
const directory = dir || this.params.mediaDir;
const filepath = path_1.default.join(directory, file);
const extension = path_1.default
.extname(file)
.replace('.', '');
try {
fs.accessSync(filepath, fs.constants.F_OK);
}
catch (e) {
throw `Can't load media: ${filepath} does not exist.`;
}
this.rootTemplate.mediaFiles.push({
file,
directory,
filepath,
extension,
prefix,
});
});
return this;
}
/**
* Parses all loaded templates and collects creationIds for slides and
* elements. This will make finding templates and elements independent
* of slide number and element name.
* @returns Promise<TemplateInfo[]>
*/
setCreationIds() {
return __awaiter(this, void 0, void 0, function* () {
const templateCreationId = [];
for (const template of this.templates) {
const creationIds = template.creationIds || (yield template.setCreationIds());
template.useCreationIds = this.params.useCreationIds;
templateCreationId.push({
name: template.name,
slides: creationIds,
});
}
return templateCreationId;
});
}
/**
* Get some info about the imported templates
* @returns Promise<PresentationInfo>
*/
getInfo() {
return __awaiter(this, void 0, void 0, function* () {
const creationIds = yield this.setCreationIds();
const info = {
templateByName: (tplName) => {
return creationIds.find((template) => template.name === tplName);
},
slidesByTemplate: (tplName) => {
var _a;
return ((_a = info.templateByName(tplName)) === null || _a === void 0 ? void 0 : _a.slides) || [];
},
slideByNumber: (tplName, slideNumber) => {
return info
.slidesByTemplate(tplName)
.find((slide) => slide.number === slideNumber);
},
elementByName: (tplName, slideNumber, elementName) => {
var _a;
return (_a = info
.slideByNumber(tplName, slideNumber)) === null || _a === void 0 ? void 0 : _a.elements.find((element) => elementName === element.name);
},
};
return info;
});
}
/**
* Determines whether template is root or default template.
* @param template
* @returns pres template
*/
isPresTemplate(template) {
return 'name' in template;
}
/**
* Add a slide from one of the imported templates by slide number or creationId.
* @param name - Name or alias of the template; must have been loaded with `Automizer.load()`
* @param slideIdentifier - Number or creationId of slide in template presentation
* @param callback - Executed after slide was added. The newly created slide will be passed to the callback as first argument.
* @returns Instance of Automizer
*/
addSlide(name, slideIdentifier, callback) {
if (this.rootTemplate === undefined) {
throw new Error('You have to set a root template first.');
}
const template = this.getTemplate(name);
const newSlide = new slide_1.Slide({
presentation: this,
template,
slideIdentifier,
});
if (this.params.autoImportSlideMasters) {
newSlide.useSlideLayout();
}
if (callback !== undefined) {
newSlide.root = this;
callback(newSlide);
}
this.rootTemplate.slides.push(newSlide);
return this;
}
/**
* Copy and modify a master and the associated layouts from template to output.
*
* @param name
* @param sourceIdentifier
* @param callback
*/
addMaster(name, sourceIdentifier, callback) {
const key = sourceIdentifier + '@' + name;
if (this.rootTemplate.masters.find((master) => master.key === key)) {
console.log('Already imported ' + key);
return this;
}
const template = this.getTemplate(name);
const newMaster = new master_1.Master({
presentation: this,
template,
sourceIdentifier,
});
if (callback !== undefined) {
newMaster.root = this;
callback(newMaster);
}
this.rootTemplate.masters.push(newMaster);
return this;
}
/**
* Searches this.templates to find template by given name.
* @internal
* @param name Alias name if given to loaded template.
* @returns template
*/
getTemplate(name) {
const template = this.templates.find((t) => t.name === name);
if (template === undefined) {
throw new Error(`Template not found: ${name}`);
}
return template;
}
/**
* Write all imports and modifications to a file.
* @param location - Filename or path for the file. Will be prefixed with 'outputDir'
* @returns summary object.
*/
write(location) {
return __awaiter(this, void 0, void 0, function* () {
yield this.finalizePresentation();
yield this.rootTemplate.archive.output(this.getLocation(location, 'output'), this.params);
const duration = (Date.now() - this.timer) / 600;
return {
status: 'finished',
duration,
file: location,
filename: path_1.default.basename(location),
templates: this.templates.length,
slides: this.rootTemplate.count('slides'),
charts: this.rootTemplate.count('charts'),
images: this.rootTemplate.count('images'),
masters: this.rootTemplate.count('masters'),
};
});
}
/**
* Create a ReadableStream from output pptx file.
* @param generatorOptions - JSZipGeneratorOptions for nodebuffer Output type
* @returns Promise<NodeJS.ReadableStream>
*/
stream(generatorOptions) {
return __awaiter(this, void 0, void 0, function* () {
yield this.finalizePresentation();
if (!this.rootTemplate.archive.stream) {
throw 'Streaming is not implemented for current archive type';
}
return this.rootTemplate.archive.stream(this.params, generatorOptions);
});
}
/**
* Pass final JSZip instance.
* @returns Promise<NodeJS.ReadableStream>
*/
getJSZip() {
return __awaiter(this, void 0, void 0, function* () {
yield this.finalizePresentation();
if (!this.rootTemplate.archive.getFinalArchive) {
throw 'GetFinalArchive is not implemented for current archive type';
}
return this.rootTemplate.archive.getFinalArchive();
});
}
finalizePresentation() {
return __awaiter(this, void 0, void 0, function* () {
yield this.writeMasterSlides();
yield this.writeSlides();
yield this.writeMediaFiles();
yield this.normalizePresentation();
yield this.applyModifyPresentationCallbacks();
// TODO: refactor content tracker, move this to root template
content_tracker_1.contentTracker.reset();
});
}
/**
* Write all masterSlides to archive.
*/
writeMasterSlides() {
return __awaiter(this, void 0, void 0, function* () {
for (const slide of this.rootTemplate.masters) {
yield this.rootTemplate.appendMasterSlide(slide);
}
});
}
/**
* Write all slides to archive.
*/
writeSlides() {
return __awaiter(this, void 0, void 0, function* () {
yield this.rootTemplate.countExistingSlides();
this.status.max = this.rootTemplate.slides.length;
for (const slide of this.rootTemplate.slides) {
yield this.rootTemplate.appendSlide(slide);
}
if (this.params.removeExistingSlides) {
yield this.rootTemplate.truncate();
}
});
}
/**
* Write all media files to archive.
*/
writeMediaFiles() {
return __awaiter(this, void 0, void 0, function* () {
for (const file of this.rootTemplate.mediaFiles) {
const data = fs.readFileSync(file.filepath);
let archiveFilename = 'ppt/media/' + file.file;
if (file.prefix) {
archiveFilename = 'ppt/media/' + file.prefix + file.file;
}
yield this.rootTemplate.archive.write(archiveFilename, data);
yield xml_helper_1.XmlHelper.appendImageExtensionToContentType(this.rootTemplate.archive, file.extension);
}
});
}
/**
* Applies all callbacks in this.modifyPresentation-array.
* The callback array can be pushed by this.modify()
*/
applyModifyPresentationCallbacks() {
return __awaiter(this, void 0, void 0, function* () {
yield xml_helper_1.XmlHelper.modifyXmlInArchive(this.rootTemplate.archive, `ppt/presentation.xml`, this.modifyPresentation);
});
}
/**
* Apply some callbacks to restore archive/xml structure
* and prevent corrupted pptx files.
*
* TODO: Use every imported image only once
* TODO: Check for lost relations
*/
normalizePresentation() {
return __awaiter(this, void 0, void 0, function* () {
this.modify(modify_presentation_helper_1.default.normalizeSlideIds);
this.modify(modify_presentation_helper_1.default.normalizeSlideMasterIds);
if (this.params.cleanup) {
if (this.params.removeExistingSlides) {
this.modify(modify_presentation_helper_1.default.removeUnusedFiles);
}
this.modify(modify_presentation_helper_1.default.removedUnusedImages);
this.modify(modify_presentation_helper_1.default.removeUnusedContentTypes);
}
});
}
modify(cb) {
this.modifyPresentation.push(cb);
return this;
}
/**
* Applies path prefix to given location string.
* @param location path and/or filename
* @param [type] template or output
* @returns location
*/
getLocation(location, type) {
switch (type) {
case 'template':
if (fs.existsSync(this.templateDir + location)) {
return this.templateDir + location;
}
else if (fs.existsSync(this.templateFallbackDir + location)) {
return this.templateFallbackDir + location;
}
else {
(0, general_helper_1.vd)('No file matches "' + location + '"');
(0, general_helper_1.vd)('@templateDir: ' + this.templateDir);
(0, general_helper_1.vd)('@templateFallbackDir: ' + this.templateFallbackDir);
}
break;
case 'output':
return this.outputDir + location;
default:
return location;
}
}
}
exports.default = Automizer;
//# sourceMappingURL=automizer.js.map