UNPKG

@amplience/dc-cli

Version:
174 lines (173 loc) 7.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handler = exports.printTree = exports.fillWhitespace = exports.TreeBuilder = exports.firstSecondThird = exports.prepareContentForTree = exports.traverseRecursive = exports.builder = exports.LOG_FILENAME = exports.desc = exports.command = void 0; const log_helpers_1 = require("../../common/log-helpers"); const path_1 = require("path"); const fs_1 = require("fs"); const util_1 = require("util"); const dc_management_sdk_js_1 = require("dc-management-sdk-js"); const content_dependancy_tree_1 = require("../../common/content-item/content-dependancy-tree"); const content_mapping_1 = require("../../common/content-mapping"); exports.command = 'tree <dir>'; exports.desc = 'Print a content dependency tree from content in the given folder.'; const LOG_FILENAME = (platform = process.platform) => (0, log_helpers_1.getDefaultLogPath)('item', 'tree', platform); exports.LOG_FILENAME = LOG_FILENAME; const builder = (yargs) => { yargs.positional('dir', { type: 'string', describe: 'Path to the content items to build a tree from. Should be in the same format as an export.' }); }; exports.builder = builder; const traverseRecursive = async (path, action) => { const dir = await (0, util_1.promisify)(fs_1.readdir)(path); dir.sort(); for (let i = 0; i < dir.length; i++) { let contained = dir[i]; contained = (0, path_1.join)(path, contained); const stat = await (0, util_1.promisify)(fs_1.lstat)(contained); if (stat.isDirectory()) { await (0, exports.traverseRecursive)(contained, action); } else { await action(contained); } } }; exports.traverseRecursive = traverseRecursive; const prepareContentForTree = async (repo) => { const contentItems = []; const schemaNames = new Set(); await (0, exports.traverseRecursive)((0, path_1.resolve)(repo.basePath), async (path) => { if ((0, path_1.extname)(path) !== '.json') { return; } let contentJSON; try { const contentText = await (0, util_1.promisify)(fs_1.readFile)(path, { encoding: 'utf8' }); contentJSON = JSON.parse(contentText); } catch (e) { console.error(`Couldn't read content item at '${path}': ${e.toString()}`); return; } schemaNames.add(contentJSON.body._meta.schema); contentItems.push({ repo: repo.repo, content: new dc_management_sdk_js_1.ContentItem(contentJSON) }); }); return new content_dependancy_tree_1.ContentDependancyTree(contentItems, new content_mapping_1.ContentMapping()); }; exports.prepareContentForTree = prepareContentForTree; const firstSecondThird = (index, total) => { return index == total - 1 ? 2 : index === 0 ? 0 : 1; }; exports.firstSecondThird = firstSecondThird; const fstPipes = ['├', '├', '└']; const circularPipes = ['╗', '║', '╝']; const circularLine = '═'; class TreeBuilder { constructor(evaluated) { this.evaluated = evaluated; this.lines = []; this.circularLinks = []; } addDependency(item, evalThis, fst, prefix) { const depth = evalThis.length - 1; const pipe = depth < 0 ? '' : fstPipes[fst] + '─ '; const circularMatch = evalThis.find(parent => parent.item == item); if (circularMatch) { this.lines.push(`${prefix}${pipe}*** (${item.owner.content.label})`); this.circularLinks.push([circularMatch.line, this.lines.length - 1]); return false; } else if (this.evaluated.has(item)) { if (depth > -1) { this.lines.push(`${prefix}${pipe}(${item.owner.content.label})`); } return false; } else { this.lines.push(`${prefix}${pipe}${item.owner.content.label}`); } evalThis.push({ item, line: this.lines.length - 1 }); this.evaluated.add(item); const filteredItems = item.dependancies.filter(dep => dep.resolved); filteredItems.forEach((dep, index) => { const subFst = (0, exports.firstSecondThird)(index, filteredItems.length); const subPrefix = depth == -1 ? '' : fst === 2 ? ' ' : '│ '; this.addDependency(dep.resolved, [...evalThis], subFst, prefix + subPrefix); }); return true; } } exports.TreeBuilder = TreeBuilder; const fillWhitespace = (original, current, char, targetLength) => { let position = original.length; let repeats = targetLength - original.length; while (position < current.length && repeats > 0) { if (current[position] != char && current[position] == ' ') { current = current.slice(0, position) + char + current.slice(position + 1); } position++; repeats--; } if (repeats > 0) { current += char.repeat(repeats); } return current; }; exports.fillWhitespace = fillWhitespace; const printTree = (item, evaluated) => { const builder = new TreeBuilder(evaluated); const result = builder.addDependency(item, [], 0, ''); if (!result) return false; const circularLinks = builder.circularLinks; const lines = builder.lines.map(line => line + ' '); const modifiedLines = [...lines]; const maxWidth = Math.max(...lines.map(x => x.length)); for (let i = 0; i < circularLinks.length; i++) { const link = circularLinks[i]; let linkDist = maxWidth + 2; for (let j = 0; j < i; j++) { const link2 = circularLinks[j]; if (link[0] <= link2[1] && link[1] >= link2[0]) { linkDist += 2; } } for (let ln = link[0]; ln <= link[1]; ln++) { const end = ln == link[0] || ln == link[1]; const original = lines[ln]; let current = modifiedLines[ln]; current = (0, exports.fillWhitespace)(original, current, end ? circularLine : ' ', linkDist); current += circularPipes[(0, exports.firstSecondThird)(ln - link[0], link[1] - link[0] + 1)]; modifiedLines[ln] = current; } } modifiedLines.forEach(line => console.log(line)); console.log(''); return true; }; exports.printTree = printTree; const handler = async (argv) => { const dir = argv.dir; const tree = await (0, exports.prepareContentForTree)({ basePath: dir, repo: new dc_management_sdk_js_1.ContentRepository() }); const evaluated = new Set(); for (let i = tree.levels.length - 1; i >= 0; i--) { const level = tree.levels[i]; console.log(`=== LEVEL ${i + 1} (${level.items.length}) ===`); level.items.forEach(item => { (0, exports.printTree)(item, evaluated); }); } let topLevelPrints = 0; if (tree.circularLinks.length > 0) { console.log(`=== CIRCULAR (${tree.circularLinks.length}) ===`); tree.circularLinks.forEach(item => { if ((0, exports.printTree)(item, evaluated)) { topLevelPrints++; } }); } console.log(`Finished. Circular Dependencies printed: ${topLevelPrints}`); }; exports.handler = handler;