UNPKG

@viewdo/dxp-story-cli

Version:

DXP Story Management CLI

330 lines 19.4 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; 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 }); exports.TemplateManager = void 0; const ActionTemplateConfiguration_1 = require("./../models/configuration/ActionTemplateConfiguration"); const typedi_1 = require("typedi"); const ConfigurationManager_1 = require("./ConfigurationManager"); const TaskService_1 = require("../services/TaskService"); const FileService_1 = require("../services/FileService"); const EpisodeConfiguration_1 = require("../models/configuration/EpisodeConfiguration"); const StoryTemplateConfiguration_1 = require("../models/configuration/StoryTemplateConfiguration"); const ConfigurationFileService_1 = require("../services/ConfigurationFileService"); const ContentType_1 = require("../models/configuration/support/ContentType"); const path_1 = __importDefault(require("path")); const promises_1 = __importDefault(require("fs/promises")); const lodash_1 = __importDefault(require("lodash")); const ConsoleService_1 = require("../services/ConsoleService"); const child_process_1 = require("child_process"); const ContentType_2 = require("../models/configuration/support/ContentType"); let TemplateManager = class TemplateManager { constructor(file_service, configuration_manager, task_service, console_service) { this.file_service = file_service; this.configuration_manager = configuration_manager; this.task_service = task_service; this.console_service = console_service; // Story Template Readers ---------------------------------------------- this.storyTemplatesDirectory = `./.dxp/templates/stories`; this.actionTemplatesDirectory = `./.dxp/templates/actions`; } get templateKeys() { return (this._templateKeys || this.file_service.listDirectories(this.storyTemplatesDirectory)); } set templateKeys(keys) { this._templateKeys = keys; } getActionTemplateDirectory(template_key) { return `${this.actionTemplatesDirectory}/${template_key}`; } _actionTemplateConfigAccessor(template_key) { return new ConfigurationFileService_1.ConfigurationFileService(`${this.getActionTemplateDirectory(template_key)}/${ActionTemplateConfiguration_1.ActionTemplateConfiguration.file_name}`, ActionTemplateConfiguration_1.ActionTemplateConfiguration); } hasActionTemplateConfig(template_key) { return this._actionTemplateConfigAccessor(template_key).exists(); } getActionTemplateConfig(template_key) { return this._actionTemplateConfigAccessor(template_key).read({}); } hasStoryTemplateConfig(template_key) { return this._storyTemplateConfigAccessor(template_key).exists(); } getStoryTemplateDirectory(story_key) { return `./stories/${story_key}`; } getStoryTemplateConfig(template_key) { return this._storyTemplateConfigAccessor(template_key).read({}); } _storyTemplateConfigAccessor(template_key) { return new ConfigurationFileService_1.ConfigurationFileService(`${this.getStoryTemplateDirectory(template_key)}/${StoryTemplateConfiguration_1.StoryTemplateConfiguration.file_name}`, StoryTemplateConfiguration_1.StoryTemplateConfiguration); } // SCAFFOLD API ---------------------------------------------- scaffoldStory(storyKey_1, organizationKey_1, templateKey_1) { return __awaiter(this, arguments, void 0, function* (storyKey, organizationKey, templateKey, extra_args = undefined) { let subTasks = [ { title: "Scaffold Story", task: () => __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const command = `npx`; let args = ['--yes', `@archer-edu/create-story@latest`, `${storyKey}`, `--dxp_org_key`, `${organizationKey}`]; if (extra_args) args = [...args, ...extra_args]; if (templateKey) args.push(`--template`, `${templateKey}`); console.log(`Running command ${command} ${args.join(' ')}`); const child = (0, child_process_1.spawn)('bash', ['-c', `${command} ${args.join(' ')}`], { stdio: 'inherit' }); child.on('exit', (code) => { if (code === 0) resolve(true); else reject(`Shell command failed with exit code ${code}`); }); child.on('error', (error) => { reject(error); }); }); }) }, { title: "Configure Story Data", task: () => { let story_config = this.configuration_manager.getStoryConfig(storyKey); story_config.key = storyKey; story_config.organizationKey = organizationKey; story_config.name = storyKey; this.configuration_manager.setStoryAssetConfig(story_config); } }, { title: "Configure Templated Data Points", task: () => { if (this.hasStoryTemplateConfig(storyKey)) { const templateConfig = this.getStoryTemplateConfig(storyKey); if (templateConfig && templateConfig.organization_configuration) { const org_config = this.configuration_manager.getOrganizationConfig(organizationKey); let templateData = templateConfig.organization_configuration.dataPoints; let orgData = org_config.dataPoints; templateData.forEach((dataPoint) => { if (!lodash_1.default.find(orgData, (d) => d.key == dataPoint.key)) { orgData.push(dataPoint); } }); this.configuration_manager.setOrganizationConfig(org_config); } } } }, { title: "Cleanup", task: () => __awaiter(this, void 0, void 0, function* () { if (this.hasStoryTemplateConfig(storyKey)) { const templateConfigPath = `${this.getStoryTemplateDirectory(storyKey)}/${StoryTemplateConfiguration_1.StoryTemplateConfiguration.file_name}`; try { yield promises_1.default.access(templateConfigPath); //file exists, remove it yield promises_1.default.unlink(templateConfigPath); } catch (err) { this.console_service.error(`Error removing file ${templateConfigPath}`); } } }) } ]; yield this.task_service.runTasks(subTasks); }); } scaffoldEpisode(story_key, episode_key, template_key) { const story_config = this.configuration_manager.getStoryConfig(story_key); const episode = new EpisodeConfiguration_1.EpisodeConfiguration({ key: episode_key, name: episode_key, isEnabled: true, }); story_config.episodes.push(episode); this.configuration_manager.saveStoryConfig(story_config); const index = story_config.episodes.length - 1; this._scaffoldEpisodeAsset(story_config, index, "html_file", ""); this._scaffoldEpisodeAsset(story_config, index, "json_file", "{}"); this._scaffoldEpisodeAsset(story_config, index, "js_file", ""); this._scaffoldEpisodeAsset(story_config, index, "css_file", ""); } _scaffoldEpisodeAsset(story_config, episode_index, asset_type, default_content) { const assets = story_config.getAssets(); const assetConfig = this.configuration_manager.getStoryAssetConfig(story_config.key); const defaultAsset = assets.find((asset) => asset.key == asset_type); const assetPath = assetConfig.getLocalPath(defaultAsset); const assetExists = this.file_service.exists(assetPath); const defaultContent = assetExists ? defaultAsset.convertFromLocal(this.file_service.read(assetPath)) : default_content; const assetKey = story_config._getEpisodeAssetKey(episode_index, asset_type); const episodeAsset = assets.find((asset) => asset.key == assetKey); this.file_service.write(episodeAsset.local_path, episodeAsset.convertFromRemote(defaultContent)); if (defaultAsset.source_path) { const sourceExists = this.file_service.exists(defaultAsset.local_path); const assetSource = sourceExists ? this.file_service.read(defaultAsset.source_path) : default_content; this.file_service.write(episodeAsset.source_path, assetSource); } } scaffoldState(story_key, state_key, state_type) { // 1. Need to define all scene types. List as array? // 2. Need to validate the stateType selected against what is avaialable // * Loop through current states and validate that the new key is unique // // Based on which state type we selected, grab the designated template (i.e. video, toc, html, cta, navigation) // * stamp it out in as a new state // 3. Need to push new state data into the designated episoded 'default-data.yml' // * Something like story_config.episodes.push(episode) // * Although, the story_config doesn't need to be updated. Just the data for the episode } scaffoldScene(story_key, episode_key, template_key, scene_key, scene_id) { const story_config = this.configuration_manager.getStoryConfig(story_key); const template_config = this.getStoryTemplateConfig(template_key); const assets = story_config.getAssets(); const assetConfig = this.configuration_manager.getStoryAssetConfig(story_config.key); // 1. Need to push new scene data into the designated episode' scenes list ('default-data.yml') // * Although, the story_config doesn't need to be updated. Just the data for the episode let episodeIndex = story_config.episodes.findIndex(p => p.key == episode_key); let assetKey = episodeIndex > 0 ? story_config._getEpisodeAssetKey(episodeIndex, "json_file") : "json_file"; const assetDef = story_config.getAssetDefinition(assetKey); const assetPath = assetConfig.getLocalPath(assetDef); if (!this.file_service.exists(assetPath)) throw new Error("The story data file does not exist: " + assetPath); const scene = template_config.scene_templates.find((s) => s.key == scene_key); scene.id = scene_id; delete scene.key; const storyDataText = assetDef.convertFromLocal(this.file_service.read(assetPath)); const storyData = JSON.parse(storyDataText); if (storyData.states.find((s) => s.id == scene_id) != null) throw new Error(`The sceneId ${scene_id} already exists.`); storyData.states.push(scene); // 2. Unpack the story-data afterwards to build out the scene folder w/any embedded HTML this.file_service.write(assetPath, assetDef.convertFromRemote(JSON.stringify(storyData))); // 3. Copy over assets from parent template to story's asset folder, // but without overwriting existing files. this.file_service.syncDirectories(template_config.templateAssetDirectory, story_config.assets_directory, false); } scaffoldTemplate(story_key, template_key, template_type) { // let fake_story = this._getFakeStory(story_key, organization_key) // let story_config = this.configuration_manager.setStoryConfig(fake_story) // this.configuration_manager.setStoryAssetConfig(story_config) } addActionTemplates(story_config, action) { // no need to manage templates for actions that don't use them if (!this.hasActionTemplateConfig(action.actionType)) return; let template_config = this.getActionTemplateConfig(action.actionType); Object.keys(action.parameters).forEach((param_key) => { let template = template_config.parameter_templates[param_key]; let param_value = action.parameters[param_key]; if (template != undefined) { let content = template.content; if (content.startsWith("./")) { let content_path = path_1.default.join(template_config.getTemplateDirectory(), content); content = this.file_service.read(content_path) || ""; } let assetDef = null; switch (template.type) { case "Email": { // Check if the template already exists in the array const exists = story_config.emailTemplates.some((existingTemplate) => existingTemplate.key === param_value); if (!exists) { const fileType = ContentType_2.contentTypeToExtension[ContentType_1.ContentType.LIQUID]; const parsedData = this.file_service.parseKeyToPathAndFile(param_value.toString()); story_config.emailTemplates.push({ key: param_value.toString(), name: story_config.getTemplateName(param_value.toString()), file: `${parsedData.file}${fileType}`, path: parsedData.path, type: ContentType_1.ContentType.LIQUID }); assetDef = story_config.getAssetDefinition(`email_templates.${param_value.toString()}`); } break; } default: { const exists = story_config.textTemplates.some((existingTemplate) => existingTemplate.key === param_value); if (!exists) { const fileType = ContentType_2.contentTypeToExtension[template.type]; const parsedData = this.file_service.parseKeyToPathAndFile(param_value.toString()); story_config.textTemplates.push({ key: param_value.toString(), name: story_config.getTemplateName(param_value.toString()), file: `${parsedData.file}${fileType}`, path: parsedData.path, type: template.type }); assetDef = story_config.getAssetDefinition(`text_templates.${param_value.toString()}`); } break; } } if (assetDef) { try { var compiled = lodash_1.default.template(content); content = compiled({ story: story_config, action, }); this.file_service.write(assetDef.local_path, content); } catch (error) { this.file_service.write(assetDef.local_path, content); } if (template.supportFiles) { template.supportFiles.forEach((s) => { let templatePath = path_1.default.join(template_config.getTemplateDirectory(), s); let supportContent = this.file_service.read(templatePath) || ""; let destinationPath = path_1.default.join(assetDef.local_path.replace(path_1.default.basename(assetDef.local_path), ""), s); try { let supportContentCompiled = lodash_1.default.template(supportContent); supportContent = supportContentCompiled({ story: story_config, action, }); } catch (error) { } this.file_service.write(destinationPath, supportContent); }); } } } }); //this.file_service.syncDirectories(template_config.getTemplateSyncDirectory(), story_config.local_root, false); } }; exports.TemplateManager = TemplateManager; exports.TemplateManager = TemplateManager = __decorate([ (0, typedi_1.Service)(), __metadata("design:paramtypes", [FileService_1.FileService, ConfigurationManager_1.ConfigurationManager, TaskService_1.TaskService, ConsoleService_1.ConsoleService]) ], TemplateManager); //# sourceMappingURL=TemplateManager.js.map