UNPKG

@viewdo/dxp-story-cli

Version:
594 lines (470 loc) 19.4 kB
const isUndefined = require('lodash/isUndefined'); const omitBy = require('lodash/omitBy'); const isObject = require('lodash/isObject'); const isEmpty = require('lodash/isEmpty'); const sortBy = require('lodash/sortBy'); const PathManager = require('./path-manager'); const fs = require('fs'); class iVXjsReader { constructor(ivx_js_config = {}, source = "./src", opts = {}) { const { story_key, episode_key } = opts; Object.assign(this, { PathManager, ivx_js_config, story_key, episode_key, handlers: [], omitBy, isUndefined, sortBy, isEmpty, isObject }); this._setUp(source) } _setUp(source) { const { story_key, episode_key, ivx_js_config = {}, PathManager } = this; const { metadata = {} } = ivx_js_config; const new_metatdata = Object.assign({}, metadata, { storyKey: story_key, }); if (episode_key) new_metatdata.episodeKey = episode_key; const updated_ivx_js_config = Object.assign({}, ivx_js_config, { metadata: new_metatdata }); const path_manager = new PathManager(source, '', { story_key: new_metatdata.storyKey, episode_key: new_metatdata.episodeKey }) Object.assign(this, { path_manager, source: path_manager.getSource(), ivx_js_config: updated_ivx_js_config, story_key: new_metatdata.storyKey, episode_key: new_metatdata.episodeKey }); return this; } read(cb = () => { }) { const { isEmpty } = this; while (!isEmpty(this.handlers)) { const handler = this.handlers.pop(); handler(); } cb(); return this; } handleiVXjsConfig(callback) { const { ivx_js_config, path_manager, story_key, episode_key } = this; const story_opts = { story_key, episode_key }; const states_folder_path = path_manager.getStatesFolderPath(); const page_elements_path = path_manager.getPageElementsFolderPath(); const metadata_path = path_manager.getMetadataFolderPath(); const static_data_path = path_manager.getStaticDataFolderPath(); const parent_states = this._getParentStates(ivx_js_config); const config_path = path_manager.getStoryConfigSourcePath(story_key, episode_key); const opts = { states_folder_path, page_elements_path, parent_states, metadata_path, static_data_path, config_path }; const ivx_js_config_opts = Object.assign({}, story_opts, opts) const handler = () => { if (callback) callback(ivx_js_config, ivx_js_config_opts); } this._addHandlers([handler]); return this; } handleStates(callback) { const self = this; const { path_manager, sortBy } = this; const states_folder_path = path_manager.getStatesFolderPath(); const common_states_folder_path = path_manager.getCommonStatesFolderPath(); const states_opts = { states_folder_path, common_states_folder_path } let states = []; let common_states = []; return this .handleiVXjsConfig((ivx_js_config) => { states_opts.ivx_js_config = ivx_js_config; states = sortBy(ivx_js_config.states, ['id']); states.forEach((state) => { const opts = self._getStateOptions(state, ivx_js_config, common_states); const { embedded_parent_states = [] } = opts; if (embedded_parent_states.length > 1) { common_states = [...common_states, state]; } }); }) .read(() => { states_opts.common_states = common_states.sort((a, b) => { if (a.id < b.id) return -1; if (a.id > b.id) return 1; return 0; }); const handler = () => { if (callback) callback(states, states_opts); } self._addHandlers([handler]); }); } handleState(callback) { const self = this; return this .handleStates((states = [], opts = {}) => { const { ivx_js_config = {}, common_states = [] } = opts; states.forEach(state => { self._createStateHandler(state, ivx_js_config, common_states, callback); }) }) .read(); } handleHtmlState(callback) { const self = this; return this .handleStates((states = [], opts = {}) => { const { ivx_js_config = {}, common_states } = opts; const html_states = states.filter(state => state.type === 'html'); html_states.forEach((html_state) => { self._createStateHandler(html_state, ivx_js_config, common_states, callback); }); }).read(); } handleVideoState(callback) { const self = this; const { path_manager } = self; return this.handleStates((states, { ivx_js_config, common_states }) => { const video_states = states.filter(state => state.type === 'video'); video_states.forEach((video_state) => { const state_opts = self._getStateOptions(video_state, ivx_js_config, common_states); const { state_path } = state_opts; const tracks_folder_path = path_manager.getTracksFolderPath(state_path); const opts = Object.assign(state_opts, { tracks_folder_path } ) const handler = () => { if (callback) callback(video_state, opts); } self._addHandlers([handler]); }); }).read(); } handleVideoTrack(callback) { const self = this; return this.handleVideoState((video_state, opts) => { const { playerSettings: player_settings = {} } = video_state; const { tracks = [] } = player_settings; const handlers = tracks.map(track => { return () => { if (callback) callback(track, video_state, opts); } }); self._addHandlers(handlers); }).read(); } handleNavigationState(callback) { const self = this; return this.handleStates((states, { common_states, ivx_js_config }) => { const navigation_states = states.filter(state => state.type === 'navigation'); navigation_states.forEach((navigation_state) => { self._createStateHandler(navigation_state, ivx_js_config, common_states, callback); }); }).read(); } handleNavigationLink(callback) { const self = this; const { path_manager } = this; return this.handleNavigationState((navigation_state, state_opts) => { const { links = [] } = navigation_state; const handlers = links.map((link, index) => { return () => { let link_opts = Object.assign(state_opts, { index }); const link_path = path_manager.getNavigationLinkFolderPath(link, navigation_state, link_opts); link_opts.link_path = link_path; if (callback) callback(link, navigation_state, link_opts); } }); self._addHandlers(handlers); }).read(); } handleInputState(callback) { const self = this; return this.handleStates((states, { ivx_js_config, common_states }) => { const input_states = states.filter(state => state.type === 'input'); input_states.forEach((input_state) => { self._createStateHandler(input_state, ivx_js_config, common_states, callback); }); }).read(); } handleInput(callback) { const self = this; const { path_manager } = this; return this.handleInputState((input_state, state_opts) => { const { inputs = [] } = input_state; const handlers = inputs.map((input, index) => { return () => { const input_path = path_manager.getInputFolderPath(input, input_state, state_opts); const input_template_path = path_manager.getTemplatesFolderPath(input_path); const input_opts = Object.assign(state_opts, { index, input_path, input_template_path }); if (callback) callback(input, input_state, input_opts); } }); self._addHandlers(handlers); }).read(); } _createStateHandler(state, ivx_js_config, common_states, callback) { const opts = this._getStateOptions(state, ivx_js_config, common_states); const handler = () => { if (callback) callback(state, opts); } this._addHandlers([handler]); } _getStateOptions(state, ivx_js_config, common_states = []) { const { path_manager } = this; const { metadata = {} } = ivx_js_config; const { storyKey: story_key, episodeKey: episode_key } = metadata; const parent_states = this._getParentStates(ivx_js_config); let opts = { ivx_js_config, common_states, story_key, episode_key }; if (state.embedded) { const { parent_state, embedded_view, embedded_parent_states } = this._getEmbeddedView(state, parent_states) || {}; opts = Object.assign(opts, { embedded_parent_states, parent_state, embedded_view }) } if (!state.embedded) { const state_embedded_views_path = path_manager.getEmbeddedViewsFolderPath(state, opts); const state_embedded_view_paths = path_manager.getEmbeddedViewFolderPaths(state, opts); opts = Object.assign(opts, { state_embedded_views_path, state_embedded_view_paths }) } if (state.type === 'navigation') { opts = Object.assign(opts, { state_links_path: path_manager.getNavigationLinksFolderPath(state, opts) }) } if (state.type === 'input') { opts = Object.assign(opts, { state_inputs_path: path_manager.getInputsFolderPath(state, opts) }) } const state_path = path_manager.getStateFolderPath(state, opts); const state_events_path = path_manager.getEventsFolderPath(state_path); const state_templates_path = path_manager.getTemplatesFolderPath(state_path); const state_paths = { state_path, state_events_path, state_templates_path } opts = Object.assign(opts, state_paths); return opts; } _getParentStates(ivx_js_config) { const { states = [] } = ivx_js_config; return states.filter(state => !state.embedded); } _getEmbeddedView(embedded_state, parent_states) { const { isUndefined } = this; let embedded_view = null; const { id: embedded_state_id } = embedded_state; const embedded_parent_states = parent_states.filter((parent_state) => { const { embeddedViews: embedded_views = [] } = parent_state; const is_child = embedded_views.reduce((is_child_check, current_embedded_view) => { if (is_child_check) return is_child_check; const { states = [] } = current_embedded_view; const contains_view = !isUndefined(states.find(state => state.stateId === embedded_state_id)); if (contains_view) embedded_view = current_embedded_view; return contains_view; }, false); return is_child; }); const parent_state = parent_states.find((parent_state) => { const { embeddedViews: embedded_views = [] } = parent_state; const is_child = embedded_views.reduce((is_child_check, current_embedded_view) => { if (is_child_check) return is_child_check; const { states = [] } = current_embedded_view; const contains_view = !isUndefined(states.find(state => state.stateId === embedded_state_id)); if (contains_view) embedded_view = current_embedded_view; return contains_view; }, false); return is_child; }); return { embedded_parent_states, parent_state, embedded_view } } handlePageElement(callback) { const self = this; return this.handleiVXjsConfig((ivx_js_config) => { const { pageElements: page_elements = [] } = ivx_js_config; const handlers = page_elements.map((page_element) => { const opts = self._getPageElementOptions(page_element, ivx_js_config); return () => { if (callback) callback(page_element, opts); } }); self._addHandlers(handlers); }).read(); } handleCtaLinkPageElement(callback) { const self = this; return this.handleiVXjsConfig((ivx_js_config) => { self._handlePageElementsByType(ivx_js_config, 'cta-link', callback); }).read(); } handleCtaOverlayPageElement(callback) { const self = this; return this.handleiVXjsConfig((ivx_js_config) => { self._handlePageElementsByType(ivx_js_config, 'overlay', callback); }).read(); } handleHtmlPageElement(callback) { const self = this; return this.handleiVXjsConfig((ivx_js_config) => { self._handlePageElementsByType(ivx_js_config, 'html', callback); }).read(); } handleImagePageElement(callback) { const self = this; return this.handleiVXjsConfig((ivx_js_config) => { self._handlePageElementsByType(ivx_js_config, 'image', callback); }).read(); } _handlePageElementsByType(ivx_js_config, type, callback) { const self = this; const { pageElements: page_elements = [] } = ivx_js_config; const typed_page_elements = page_elements.filter(pageElement => pageElement.type === type); const handlers = typed_page_elements.map((page_element) => { const opts = self._getPageElementOptions(page_element, ivx_js_config); return () => { if (callback) callback(page_element, opts); } }); this._addHandlers(handlers); } _getPageElementOptions(page_element, ivx_js_config) { const { path_manager } = this; const { metadata = {} } = ivx_js_config; const { storyKey: story_key, episodeKey: episode_key } = metadata; const story_opts = { story_key, episode_key } const page_element_path = path_manager.getPageElementFolderPath(page_element, story_opts); const page_element_events_path = path_manager.getEventsFolderPath(page_element_path); const page_element_templates_path = path_manager.getTemplatesFolderPath(page_element_path); return Object.assign(story_opts, { ivx_js_config, page_element_path, page_element_templates_path, page_element_events_path }); } handleMetadata(callback) { const self = this; const { path_manager } = this; return this.handleiVXjsConfig((ivx_js_config) => { const handler = () => { const { metadata = {} } = ivx_js_config; const { storyKey: story_key, episodeKey: episode_key } = metadata; const metadata_path = path_manager.getMetadataFolderPath(); const opts = { metadata_path, story_key, episode_key } if (callback) callback(metadata, opts); } self._addHandlers([handler]); }).read(); } handleStaticData(callback) { const self = this; const { path_manager, omitBy, isObject } = this; return this.handleMetadata(metadata => { const handler = () => { const { data: static_data = {}, storyKey: story_key, episodeKey: episode_key } = metadata; const story_opts = { story_key, episode_key }; const static_data_path = path_manager.getStaticDataFolderPath(); const complex_data = Object.keys(static_data) .reduce((current_complex_data, key) => { const current_data = static_data[key]; const is_complex = Array.isArray(current_data) || isObject(current_data); if (is_complex) current_complex_data[key] = current_data; return current_complex_data; }, {}) const static_data_complex_paths = path_manager.getStaticDataPaths(static_data); const basic_data = omitBy(static_data, (property, key) => { return static_data_complex_paths.find((data) => data.key === key); }); const opts = Object.assign(story_opts, { static_data_path, static_data_complex_paths, basic_data, complex_data }); if (callback) callback(static_data, opts); } self._addHandlers([handler]); }).read(); } _getBasicData(data_obj) { const self = this; return Object.keys(data_obj).reduce((basic_data, key) => { const value = data_obj[key]; if (!self._isComplex(value)) basic_data[key] = value; return basic_data; }, {}); } _getComplexData(data_obj) { const self = this; return Object.keys(data_obj).reduce((basic_data, key) => { const value = data_obj[key]; if (self._isComplex(value)) basic_data[key] = value; return basic_data; }, {}); } _isComplex(value) { const { isObject } = this; return isObject(value) || Array.isArray(value); } _addHandlers(handlers) { const old_handlers = [...this.handlers]; Object.assign(this, { handlers: [ ...handlers, ...old_handlers ] }); } } module.exports = iVXjsReader;