import { join, parse } from 'path'; import { empty, from, merge, Observable, of } from 'rxjs'; import { distinct, filter, map, mergeMap } from 'rxjs/operators'; import { optNormalizeDir } from '../options'; import { FileDescriptor, rxGetFileDescriptor } from './rx.walk'; import { IdMapping, Matcher, WchTools } from './wchtools'; interface Cycle { [key: string]: any; } function _rxGetContentDependencies(aContentId: string, aTools: WchTools, aCycle: Cycle): Observable { // check if we have a type if (aContentId) { // check if (!aCycle[aContentId]) { // add the dependency aCycle[aContentId] = aContentId; // asset file const contentFile = aTools.idToFile[aContentId]; // get the type const content = aTools.content[aContentId]; // check if (contentFile && content) { // add the asset file const res: Observable[] = []; res.push(of(contentFile)); // iterate over the elements if (content.elements) { // iterate Object.keys(content.elements).forEach(key => { const el = content.elements[key]; if (el.elementType === 'reference') { // check values if (el.values) { el.values.forEach((v: any) => res.push(_rxGetContentDependencies(v, aTools, aCycle))); } if (el.value) { res.push(_rxGetContentDependencies(el.value, aTools, aCycle)) } } else if ((el.elementType === 'image') && el.asset && el.asset.id) { // copy the image res.push(_rxGetAssetDependencies(el.asset.id, aTools, aCycle)); } }); } // thumb if (content.thumbnail && content.thumbnail.id) { res.push(_rxGetAssetDependencies(content.thumbnail.id, aTools, aCycle)); } // type if (content.typeId) { res.push(_rxGetTypeDependencies(content.typeId, aTools, aCycle)); } // merge return merge(...res); } // nothing return empty(); } } // nothing return empty(); } function _rxGetAssetDependencies(aAssetId: string, aTools: WchTools, aCycle: Cycle): Observable { // check if we have a type if (aAssetId) { // check if (!aCycle[aAssetId]) { // add the dependency aCycle[aAssetId] = aAssetId; // handle the assets return aTools.rxAssets.pipe(mergeMap, string>(assets => { // asset file const assetFile = aTools.idToFile[aAssetId]; // get the type const asset = assets[aAssetId]; // check if (assetFile && asset) { // add the asset file const res: Observable[] = []; res.push(of(assetFile)); // resolve the asset const path = parse(assetFile); // append the binary asset const assetBinaryFile = join(path.dir, asset.fileName); res.push(of(assetBinaryFile)); // append the renditions res.push(aTools.rxRenditions.pipe( map(renditions => Object.keys(renditions). filter(key => renditions[key].asset.id === aAssetId). map(key => aTools.idToFile[key])), mergeMap(files => from(files)) )); // merge return merge(...res); } // nothing return empty(); })); } } // nothing return empty(); } function _rxGetTypeDependencies(aTypeId: string, aTools: WchTools, aCycle: Cycle): Observable { // check if we have a type if (aTypeId) { // check if (!aCycle[aTypeId]) { // add the dependency aCycle[aTypeId] = aTypeId; // the type itself const typeFile = aTools.idToFile[aTypeId]; // get the type const type = aTools.types[aTypeId]; // handle if (typeFile && type) { // handle dependencies const res: Observable[] = []; res.push(of(typeFile)); // thumbnail const thumb = type['thumbnail']; if (thumb) { res.push(_rxGetAssetDependencies(thumb, aTools, aCycle)); } // ok return merge(...res); } } } // nothing return empty(); } export function rxGetTypeDependencies(aTypeId: string, aTools: WchTools): Observable { return _rxGetTypeDependencies(aTypeId, aTools, {}); } export function rxGetContentDependencies(aMatcher: Matcher, aTools: WchTools): Observable { // make sure the root ends with a slahs const prefix = optNormalizeDir(aTools.root); // cycle const cycle: Cycle = {}; // iterate over all content items const rxTotal = merge(...Object.keys(aTools.content).filter(key => aMatcher(aTools.content[key].name)).map(key => _rxGetContentDependencies(key, aTools, cycle))).pipe( filter(file => file.startsWith(prefix)), distinct(), mergeMap(file => rxGetFileDescriptor(file, prefix)) ); // ok return rxTotal; }