134 lines
3.8 KiB
JavaScript
134 lines
3.8 KiB
JavaScript
/*
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
Author Tobias Koppers @sokra
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const { HookMap, SyncWaterfallHook, SyncBailHook } = require("tapable");
|
|
|
|
/**
|
|
* @typedef {Object} PrintedElement
|
|
* @property {string} element
|
|
* @property {string} content
|
|
*/
|
|
|
|
const forEachLevel = (hookMap, type, fn) => {
|
|
const typeParts = type.split(".");
|
|
for (let i = 0; i < typeParts.length; i++) {
|
|
const hook = hookMap.get(typeParts.slice(i).join("."));
|
|
if (hook) {
|
|
const result = fn(hook);
|
|
if (result !== undefined) return result;
|
|
}
|
|
}
|
|
};
|
|
|
|
const forEachLevelWaterfall = (hookMap, type, data, fn) => {
|
|
const typeParts = type.split(".");
|
|
for (let i = 0; i < typeParts.length; i++) {
|
|
const hook = hookMap.get(typeParts.slice(i).join("."));
|
|
if (hook) {
|
|
data = fn(hook, data);
|
|
}
|
|
}
|
|
return data;
|
|
};
|
|
|
|
class StatsPrinter {
|
|
constructor() {
|
|
this.hooks = Object.freeze({
|
|
/** @type {HookMap<SyncBailHook<[string[], Object]>>} */
|
|
sortElements: new HookMap(
|
|
() => new SyncBailHook(["elements", "context"])
|
|
),
|
|
/** @type {HookMap<SyncBailHook<[PrintedElement[], Object]>>} */
|
|
printElements: new HookMap(
|
|
() => new SyncBailHook(["printedElements", "context"])
|
|
),
|
|
/** @type {HookMap<SyncBailHook<[any[], Object]>>} */
|
|
sortItems: new HookMap(() => new SyncBailHook(["items", "context"])),
|
|
/** @type {HookMap<SyncBailHook<[any, Object]>>} */
|
|
getItemName: new HookMap(() => new SyncBailHook(["item", "context"])),
|
|
/** @type {HookMap<SyncBailHook<[string[], Object]>>} */
|
|
printItems: new HookMap(
|
|
() => new SyncBailHook(["printedItems", "context"])
|
|
),
|
|
/** @type {HookMap<SyncBailHook<[Object, Object]>>} */
|
|
print: new HookMap(() => new SyncBailHook(["object", "context"])),
|
|
/** @type {HookMap<SyncWaterfallHook<[string, Object]>>} */
|
|
result: new HookMap(() => new SyncWaterfallHook(["result", "context"]))
|
|
});
|
|
}
|
|
|
|
print(type, object, baseContext) {
|
|
const context = {
|
|
...baseContext,
|
|
type,
|
|
[type]: object
|
|
};
|
|
|
|
let printResult = forEachLevel(this.hooks.print, type, hook =>
|
|
hook.call(object, context)
|
|
);
|
|
if (printResult === undefined) {
|
|
if (Array.isArray(object)) {
|
|
const sortedItems = object.slice();
|
|
forEachLevel(this.hooks.sortItems, type, h =>
|
|
h.call(sortedItems, context)
|
|
);
|
|
const printedItems = sortedItems.map((item, i) => {
|
|
const itemContext = {
|
|
...context,
|
|
_index: i
|
|
};
|
|
const itemName = forEachLevel(
|
|
this.hooks.getItemName,
|
|
`${type}[]`,
|
|
h => h.call(item, itemContext)
|
|
);
|
|
if (itemName) itemContext[itemName] = item;
|
|
return this.print(
|
|
itemName ? `${type}[].${itemName}` : `${type}[]`,
|
|
item,
|
|
itemContext
|
|
);
|
|
});
|
|
printResult = forEachLevel(this.hooks.printItems, type, h =>
|
|
h.call(printedItems, context)
|
|
);
|
|
if (printResult === undefined) {
|
|
const result = printedItems.filter(Boolean);
|
|
if (result.length > 0) printResult = result.join("\n");
|
|
}
|
|
} else if (object !== null && typeof object === "object") {
|
|
const elements = Object.keys(object);
|
|
forEachLevel(this.hooks.sortElements, type, h =>
|
|
h.call(elements, context)
|
|
);
|
|
const printedElements = elements.map(element => {
|
|
const content = this.print(`${type}.${element}`, object[element], {
|
|
...context,
|
|
_parent: object,
|
|
_element: element,
|
|
[element]: object[element]
|
|
});
|
|
return { element, content };
|
|
});
|
|
printResult = forEachLevel(this.hooks.printElements, type, h =>
|
|
h.call(printedElements, context)
|
|
);
|
|
if (printResult === undefined) {
|
|
const result = printedElements.map(e => e.content).filter(Boolean);
|
|
if (result.length > 0) printResult = result.join("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
return forEachLevelWaterfall(this.hooks.result, type, printResult, (h, r) =>
|
|
h.call(r, context)
|
|
);
|
|
}
|
|
}
|
|
module.exports = StatsPrinter;
|