@amplience/dc-cli
Version:
Dynamic Content CLI Tool
174 lines (173 loc) • 7.27 kB
JavaScript
;
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;