@oaklean/profiler-core
Version:
Part of the @oaklean suite. It provides all basic functions to work with the `.oak` file format. It allows parsing the `.oak` file format as well as tools for analyzing the measurement values. It also provides all necessary capabilities required for prec
810 lines • 85.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SourceFileMetaDataTree = void 0;
const fs = __importStar(require("fs"));
const glob_to_regexp_1 = __importDefault(require("glob-to-regexp"));
const BaseModel_1 = require("./BaseModel");
const ModelMap_1 = require("./ModelMap");
const SourceFileMetaData_1 = require("./SourceFileMetaData");
const SourceNodeMetaData_1 = require("./SourceNodeMetaData");
const NodeModule_1 = require("./NodeModule");
const SensorValues_1 = require("./SensorValues");
const PathIndex_1 = require("./indices/PathIndex");
const GlobalIndex_1 = require("./indices/GlobalIndex");
const env_1 = require("../constants/env");
const UnifiedPath_1 = require("../system/UnifiedPath");
const LoggerHelper_1 = require("../helper/LoggerHelper");
const SetHelper_1 = require("../helper/SetHelper");
const PermissionHelper_1 = require("../helper/PermissionHelper");
// Types
const types_1 = require("../types");
class SourceFileMetaDataTree extends BaseModel_1.BaseModel {
constructor(type, filePath, index) {
super();
this.type = type;
this.filePath = filePath;
this.index = index;
}
globalIndex() {
switch (this.type) {
case types_1.SourceFileMetaDataTreeType.Root:
return this
.index;
case types_1.SourceFileMetaDataTreeType.File:
return this
.index.moduleIndex.globalIndex;
case types_1.SourceFileMetaDataTreeType.Directory:
case types_1.SourceFileMetaDataTreeType.Module:
return this.index.globalIndex;
}
throw new Error('SourceFileMetaDataTree.globalIndex: unexpected type');
}
static isRootNode(data) {
return data.type === types_1.SourceFileMetaDataTreeType.Root;
}
static isFileNode(data) {
return data.type === types_1.SourceFileMetaDataTreeType.File;
}
static isDirectoryNode(data) {
return data.type === types_1.SourceFileMetaDataTreeType.Directory;
}
static isModuleNode(data) {
return data.type === types_1.SourceFileMetaDataTreeType.Module;
}
isRoot() {
return SourceFileMetaDataTree.isRootNode(this);
}
isFile() {
return SourceFileMetaDataTree.isFileNode(this);
}
isDirectory() {
return SourceFileMetaDataTree.isDirectoryNode(this);
}
isModule() {
return SourceFileMetaDataTree.isModuleNode(this);
}
get headlessSensorValues() {
if (this._headlessSensorValues === undefined) {
this._headlessSensorValues = new SensorValues_1.SensorValues({});
}
return this._headlessSensorValues;
}
set headlessSensorValues(value) {
this._headlessSensorValues = value;
}
get aggregatedLangInternalSourceNodeMetaData() {
if (!this._aggregatedLangInternalSourceNodeMetaData) {
this._aggregatedLangInternalSourceNodeMetaData =
new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, new SensorValues_1.SensorValues({}), undefined), new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, new SensorValues_1.SensorValues({}), undefined));
}
return this._aggregatedLangInternalSourceNodeMetaData;
}
get aggregatedInternSourceMetaData() {
if (!this._aggregatedInternSourceMetaData) {
this._aggregatedInternSourceMetaData = new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, new SensorValues_1.SensorValues({}), undefined), new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, new SensorValues_1.SensorValues({}), undefined));
}
return this._aggregatedInternSourceMetaData;
}
get aggregatedExternSourceMetaData() {
if (!this._aggregatedExternSourceMetaData) {
this._aggregatedExternSourceMetaData = new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, new SensorValues_1.SensorValues({}), undefined), new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, new SensorValues_1.SensorValues({}), undefined));
}
return this._aggregatedExternSourceMetaData;
}
get totalAggregatedSourceMetaData() {
return SourceFileMetaData_1.AggregatedSourceNodeMetaData.join(this.aggregatedLangInternalSourceNodeMetaData, this.aggregatedInternSourceMetaData, this.aggregatedExternSourceMetaData);
}
get langInternalChildren() {
if (!this._langInternalChildren) {
this._langInternalChildren = new ModelMap_1.ModelMap('string');
}
return this._langInternalChildren;
}
get internChildren() {
if (!this._internChildren) {
this._internChildren = new ModelMap_1.ModelMap('string');
}
return this._internChildren;
}
get externChildren() {
if (!this._externChildren) {
this._externChildren = new ModelMap_1.ModelMap('string');
}
return this._externChildren;
}
storeToFile(filePath, kind) {
switch (kind !== undefined ? kind : 'json') {
case 'pretty-json':
PermissionHelper_1.PermissionHelper.writeFileWithUserPermission(filePath, JSON.stringify(this, null, 2));
break;
case 'json':
PermissionHelper_1.PermissionHelper.writeFileWithUserPermission(filePath, JSON.stringify(this));
break;
default:
break;
}
}
validate() {
var _a, _b, _c, _d;
if (this.type === types_1.SourceFileMetaDataTreeType.File) {
(_a = this.linkedMetaData) === null || _a === void 0 ? void 0 : _a.sourceFileMetaData.validate();
return;
}
const totals = [];
const maxs = [];
for (const sourceFileMetaData of this.internChildren.values()) {
totals.push(sourceFileMetaData.aggregatedInternSourceMetaData.total);
maxs.push(sourceFileMetaData.aggregatedInternSourceMetaData.max);
}
const total = SourceNodeMetaData_1.SourceNodeMetaData.sum(...totals);
const max = SourceNodeMetaData_1.SourceNodeMetaData.max(...maxs);
if (this.type === types_1.SourceFileMetaDataTreeType.Root) {
total.sensorValues.addToAggregated(this.headlessSensorValues);
}
if (total.sensorValues.aggregatedCPUTime >
total.sensorValues.selfCPUTime +
total.sensorValues.internCPUTime +
total.sensorValues.externCPUTime +
total.sensorValues.langInternalCPUTime ||
total.sensorValues.aggregatedCPUEnergyConsumption >
total.sensorValues.selfCPUEnergyConsumption +
total.sensorValues.internCPUEnergyConsumption +
total.sensorValues.externCPUEnergyConsumption +
total.sensorValues.langInternalCPUEnergyConsumption ||
total.sensorValues.aggregatedRAMEnergyConsumption >
total.sensorValues.selfRAMEnergyConsumption +
total.sensorValues.internRAMEnergyConsumption +
total.sensorValues.externRAMEnergyConsumption +
total.sensorValues.langInternalRAMEnergyConsumption) {
LoggerHelper_1.LoggerHelper.error(total.sensorValues, (_b = this.filePath) === null || _b === void 0 ? void 0 : _b.toString());
throw new Error('SourceFileMetaDataTree.validate: Assertion error aggregatedCPUTime is not correct');
}
if (!SourceNodeMetaData_1.SourceNodeMetaData.equals(this.aggregatedInternSourceMetaData.max, max)) {
LoggerHelper_1.LoggerHelper.error(max, this.aggregatedInternSourceMetaData.max, (_c = this.filePath) === null || _c === void 0 ? void 0 : _c.toString());
throw new Error('SourceFileMetaDataTree.validate: Assertion error max is not correct ' +
((_d = this.filePath) === null || _d === void 0 ? void 0 : _d.toString()));
}
}
toJSON() {
var _a, _b, _c, _d, _e;
if (env_1.NODE_ENV === 'test') {
this.validate();
}
return {
headlessSensorValues: (_a = this._headlessSensorValues) === null || _a === void 0 ? void 0 : _a.toJSON(),
aggregatedLangInternalSourceNodeMetaData: (_b = this._aggregatedLangInternalSourceNodeMetaData) === null || _b === void 0 ? void 0 : _b.toJSON(),
aggregatedInternSourceMetaData: (_c = this._aggregatedInternSourceMetaData) === null || _c === void 0 ? void 0 : _c.toJSON(),
aggregatedExternSourceMetaData: (_d = this._aggregatedExternSourceMetaData) === null || _d === void 0 ? void 0 : _d.toJSON(),
type: this.type,
filePath: (_e = this.filePath) === null || _e === void 0 ? void 0 : _e.toJSON(),
langInternalChildren: this.langInternalChildren.toJSON(),
internChildren: this.internChildren.toJSON() || {},
externChildren: this.externChildren.toJSON(),
linkedMetaData: this.linkedMetaData === undefined
? undefined
: {
internReportID: this.linkedMetaData.internReportID,
sourceFileMetaData: this.linkedMetaData.sourceFileMetaData.toJSON()
},
globalIndex: (this.isRoot()
? this.index.toJSON()
: undefined),
engineModule: (this.isRoot()
? this.index.engineModule.toJSON()
: undefined)
};
}
static fromJSON(json, type, indexFromParent) {
var _a, _b, _c, _d;
let data;
if (typeof json === 'string') {
data = JSON.parse(json);
}
else {
data = json;
}
let index;
if (type !== data.type) {
throw new Error('SourceFileMetaDataTree.fromJSON: given type and type of input data is not the same');
}
if (SourceFileMetaDataTree.isRootNode(data)) {
if (data.globalIndex === undefined) {
throw new Error('SourceFileMetaDataTree.fromJSON: input does not contain a globalIndex');
}
index = GlobalIndex_1.GlobalIndex.fromJSON(data.globalIndex, NodeModule_1.NodeModule.fromJSON(data
.engineModule));
}
else {
if (indexFromParent === undefined) {
throw new Error('SourceFileMetaDataTree.fromJSON: indexFromParent must be given for non root nodes');
}
index = indexFromParent;
}
const result = new SourceFileMetaDataTree(data.type, (data.type === types_1.SourceFileMetaDataTreeType.File ||
data.type === types_1.SourceFileMetaDataTreeType.Directory ||
data.type === types_1.SourceFileMetaDataTreeType.Module
? new UnifiedPath_1.UnifiedPath(data.filePath)
: undefined), index);
if (data.headlessSensorValues) {
result._headlessSensorValues = SensorValues_1.SensorValues.fromJSON(data.headlessSensorValues);
}
if (data.aggregatedLangInternalSourceNodeMetaData) {
result._aggregatedLangInternalSourceNodeMetaData =
SourceFileMetaData_1.AggregatedSourceNodeMetaData.fromJSON(data.aggregatedLangInternalSourceNodeMetaData);
}
if (data.aggregatedInternSourceMetaData) {
result._aggregatedInternSourceMetaData =
SourceFileMetaData_1.AggregatedSourceNodeMetaData.fromJSON(data.aggregatedInternSourceMetaData);
}
if (data.aggregatedExternSourceMetaData) {
result._aggregatedExternSourceMetaData =
SourceFileMetaData_1.AggregatedSourceNodeMetaData.fromJSON(data.aggregatedExternSourceMetaData);
}
if (data.linkedMetaData !== undefined) {
if (index === undefined) {
throw new Error('SourceFileMetaDataTree.fromJSON: pathIndex is missing');
}
result.linkedMetaData = {
internReportID: data.linkedMetaData.internReportID,
sourceFileMetaData: SourceFileMetaData_1.SourceFileMetaData.fromJSON(data.linkedMetaData.sourceFileMetaData, index)
};
}
if (data.langInternalChildren) {
for (const [langInternalPath, subTree] of Object.entries(data.langInternalChildren)) {
const indexToPass = type === types_1.SourceFileMetaDataTreeType.Root
? (_a = index
.getLangInternalIndex('get')) === null || _a === void 0 ? void 0 : _a.getFilePathIndex('get', subTree.filePath)
: (_c = (_b = index === null || index === void 0 ? void 0 : index.globalIndex) === null || _b === void 0 ? void 0 : _b.getLangInternalIndex('get')) === null || _c === void 0 ? void 0 : _c.getFilePathIndex('get', subTree.filePath);
if (indexToPass === undefined) {
LoggerHelper_1.LoggerHelper.error(index.getModuleIndex('get'));
throw new Error('SourceFileMetaDataTree.fromJSON: (langInternal children) could not resolve index for subTree');
}
result.langInternalChildren.set(langInternalPath, SourceFileMetaDataTree.fromJSON(subTree, subTree.type, indexToPass));
}
}
if (data.internChildren) {
for (const [filePart, subTree] of Object.entries(data.internChildren)) {
let indexToPass;
switch (subTree.type) {
case types_1.SourceFileMetaDataTreeType.Directory:
indexToPass =
type === types_1.SourceFileMetaDataTreeType.Root
? index.getModuleIndex('get')
: index;
break;
case types_1.SourceFileMetaDataTreeType.File:
indexToPass =
type === types_1.SourceFileMetaDataTreeType.Root
? (_d = index
.getModuleIndex('get')) === null || _d === void 0 ? void 0 : _d.getFilePathIndex('get', subTree.filePath)
: index.getFilePathIndex('get', subTree.filePath);
break;
default:
throw new Error('SourceFileMetaDataTree.fromJSON: unexpected subTree type');
}
if (indexToPass === undefined) {
LoggerHelper_1.LoggerHelper.error(index.getModuleIndex('get'));
throw new Error('SourceFileMetaDataTree.fromJSON: (intern children) could not resolve index for subTree');
}
result.internChildren.set(filePart, SourceFileMetaDataTree.fromJSON(subTree, subTree.type, indexToPass));
}
}
if (data.externChildren) {
for (const [moduleIdentifier, subTree] of Object.entries(data.externChildren)) {
let indexToPass;
switch (type) {
case types_1.SourceFileMetaDataTreeType.Root:
indexToPass = index.getModuleIndex('get', moduleIdentifier);
break;
case types_1.SourceFileMetaDataTreeType.Module:
indexToPass = index.globalIndex.getModuleIndex('get', moduleIdentifier);
break;
case types_1.SourceFileMetaDataTreeType.Directory:
case types_1.SourceFileMetaDataTreeType.File:
default:
throw new Error('SourceFileMetaDataTree.fromJSON: unexpected subTree type');
}
if (indexToPass === undefined) {
throw new Error('SourceFileMetaDataTree.fromJSON: (extern children) could not resolve index for subTree');
}
result.externChildren.set(moduleIdentifier, SourceFileMetaDataTree.fromJSON(subTree, subTree.type, indexToPass));
}
}
return result;
}
static loadFromFile(filePath) {
if (!fs.existsSync(filePath.toPlatformString())) {
return undefined;
}
return SourceFileMetaDataTree.fromJSON(fs.readFileSync(filePath.toPlatformString()).toString(), types_1.SourceFileMetaDataTreeType.Root, undefined);
}
addToAggregatedLangInternalSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData) {
this.aggregatedLangInternalSourceNodeMetaData.total =
SourceNodeMetaData_1.SourceNodeMetaData.sum(this.aggregatedLangInternalSourceNodeMetaData.total, aggregatedSourceNodeMetaData.total);
this.aggregatedLangInternalSourceNodeMetaData.max = SourceNodeMetaData_1.SourceNodeMetaData.max(this.aggregatedLangInternalSourceNodeMetaData.max, aggregatedSourceNodeMetaData.max);
}
addToAggregatedInternSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData) {
this.aggregatedInternSourceMetaData.total = SourceNodeMetaData_1.SourceNodeMetaData.sum(this.aggregatedInternSourceMetaData.total, aggregatedSourceNodeMetaData.total);
this.aggregatedInternSourceMetaData.max = SourceNodeMetaData_1.SourceNodeMetaData.max(this.aggregatedInternSourceMetaData.max, aggregatedSourceNodeMetaData.max);
}
addToAggregatedExternSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData) {
this.aggregatedExternSourceMetaData.total = SourceNodeMetaData_1.SourceNodeMetaData.sum(this.aggregatedExternSourceMetaData.total, aggregatedSourceNodeMetaData.total);
this.aggregatedExternSourceMetaData.max = SourceNodeMetaData_1.SourceNodeMetaData.max(this.aggregatedExternSourceMetaData.max, aggregatedSourceNodeMetaData.max);
}
static fromProjectReport(projectReport) {
const tree = new SourceFileMetaDataTree(types_1.SourceFileMetaDataTreeType.Root, undefined, projectReport.globalIndex);
tree.addProjectReport(projectReport);
tree.headlessSensorValues = SensorValues_1.SensorValues.fromJSON(projectReport.headlessSensorValues.toJSON());
return tree;
}
insertLangInternalPath(internReportID, langInternalPath, aggregatedSourceNodeMetaData, sourceFileMetaData) {
var _a;
this.addToAggregatedLangInternalSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData);
let child = this.langInternalChildren.get(langInternalPath);
if (!child) {
const moduleIndex = (_a = (this.isRoot()
? this.index.getModuleIndex('get')
: this.index)) === null || _a === void 0 ? void 0 : _a.globalIndex.getLangInternalIndex('get');
const pathIndex = moduleIndex === null || moduleIndex === void 0 ? void 0 : moduleIndex.getFilePathIndex('get', langInternalPath);
if (pathIndex === undefined) {
throw new Error('SourceFileMetaDataTree.insertLangInternalPath: could not resolve path index');
}
child = new SourceFileMetaDataTree(types_1.SourceFileMetaDataTreeType.File, new UnifiedPath_1.UnifiedPath(langInternalPath), pathIndex);
child.linkedMetaData = {
internReportID,
sourceFileMetaData
};
child.addToAggregatedInternSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData);
this.langInternalChildren.set(langInternalPath, child);
return child;
}
else {
throw new Error('SourceFileMetaDataTree.insertLangInternalPath: path was already inserted ' +
`${langInternalPath}`);
}
}
insertPath(internReportID, filePathParts, aggregatedSourceNodeMetaData, sourceFileMetaData) {
this.addToAggregatedInternSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData);
let child = this.internChildren.get(filePathParts[0]);
const filePath = this.type === types_1.SourceFileMetaDataTreeType.Module
? new UnifiedPath_1.UnifiedPath('./')
: this.filePath === undefined
? new UnifiedPath_1.UnifiedPath('./')
: this.filePath;
if (filePathParts.length === 1) {
if (!child) {
const moduleIndex = this.isRoot()
? this.index.getModuleIndex('get')
: this.index;
const pathIndex = moduleIndex === null || moduleIndex === void 0 ? void 0 : moduleIndex.getFilePathIndex('get', filePath.join(...filePathParts).toString());
if (pathIndex === undefined) {
throw new Error('SourceFileMetaDataTree.insertPath: could not resolve path index');
}
child = new SourceFileMetaDataTree(types_1.SourceFileMetaDataTreeType.File, filePath.join(filePathParts[0]), pathIndex);
child.linkedMetaData = {
internReportID,
sourceFileMetaData
};
child.addToAggregatedInternSourceNodeMetaDataOfTree(aggregatedSourceNodeMetaData);
this.internChildren.set(filePathParts[0], child);
return child;
}
else {
throw new Error('SourceFileMetaDataTree.insertPath: path was already inserted ' +
`${filePath.toString()}/${filePathParts[0]}`);
}
}
if (!child) {
const moduleIndex = this.isRoot()
? this.index.getModuleIndex('get')
: this.index;
if (moduleIndex === undefined) {
throw new Error('SourceFileMetaDataTree.insertPath: could not resolve module index');
}
child = new SourceFileMetaDataTree(types_1.SourceFileMetaDataTreeType.Directory, filePath.toString() === ''
? new UnifiedPath_1.UnifiedPath(filePathParts[0])
: filePath.join(filePathParts[0]), moduleIndex);
this.internChildren.set(filePathParts[0], child);
}
return child.insertPath(internReportID, filePathParts.slice(1), aggregatedSourceNodeMetaData, sourceFileMetaData);
}
addExternReport(sourceNodeGraph, moduleReport, index) {
const child = new SourceFileMetaDataTree(types_1.SourceFileMetaDataTreeType.Module, new UnifiedPath_1.UnifiedPath('node_modules/' + moduleReport.nodeModule.identifier), index);
child.addInternReport(sourceNodeGraph, moduleReport);
for (const [moduleID, externModuleReport] of moduleReport.extern.entries()) {
const childIndex = index.globalIndex.getModuleIndexByID(moduleID);
if (childIndex === undefined) {
throw new Error('SourceFileMetaDataTree.addExternReport: could not resolve module index');
}
child.addExternReport(sourceNodeGraph, externModuleReport, childIndex);
}
this.addToAggregatedExternSourceNodeMetaDataOfTree(child.totalAggregatedSourceMetaData);
this.externChildren.set(moduleReport.nodeModule.identifier, child);
}
addInternReport(sourceNodeGraph, report) {
for (const [filePathID, sourceFileMetaData] of report.lang_internal.entries()) {
const filePathIndex = report.getPathIndexByID(filePathID);
if (filePathIndex === undefined) {
throw new Error(`SourceFileMetaDataTree.addInternReport: could not resolve path from pathID: ${filePathID}`);
}
const aggregatedSourceNodeMetaData = new SourceFileMetaData_1.AggregatedSourceNodeMetaData(sourceFileMetaData.totalSourceNodeMetaData(sourceNodeGraph).sum, sourceFileMetaData.maxSourceNodeMetaData());
this.insertLangInternalPath(report.internID, filePathIndex.identifier, aggregatedSourceNodeMetaData, sourceFileMetaData);
}
for (const [filePathID, sourceFileMetaData] of report.intern.entries()) {
const filePathIndex = report.getPathIndexByID(filePathID);
if (filePathIndex === undefined) {
throw new Error(`SourceFileMetaDataTree.addInternReport: could not resolve path from pathID: ${filePathID}`);
}
const filePathParts = new UnifiedPath_1.UnifiedPath(filePathIndex.identifier).split();
const aggregatedSourceNodeMetaData = new SourceFileMetaData_1.AggregatedSourceNodeMetaData(sourceFileMetaData.totalSourceNodeMetaData(sourceNodeGraph).sum, sourceFileMetaData.maxSourceNodeMetaData());
this.insertPath(report.internID, filePathParts, aggregatedSourceNodeMetaData, sourceFileMetaData);
}
}
addProjectReport(projectReport) {
if (!this.isRoot()) {
throw new Error('SourceFileMetaDataTree.addProjectReport: can only be executed on root nodes');
}
this.addInternReport(projectReport.asSourceNodeGraph(), projectReport);
for (const [moduleID, externModuleReport] of projectReport.extern.entries()) {
const childIndex = this.index.getModuleIndexByID(moduleID);
if (childIndex === undefined) {
throw new Error('SourceFileMetaDataTree.addExternReport: could not resolve module index');
}
this.addExternReport(projectReport.asSourceNodeGraph(), externModuleReport, childIndex);
}
}
_mergeReferences(...references) {
const result = new ModelMap_1.ModelMap('number');
for (const reference of references) {
for (const [pathID, sensorValues] of reference.entries()) {
const accumulatedSensorValues = result.get(pathID);
if (accumulatedSensorValues !== undefined) {
result.set(pathID, SensorValues_1.SensorValues.sum(accumulatedSensorValues, sensorValues));
}
else {
result.set(pathID, sensorValues);
}
}
}
return result;
}
filter(sourceNodeGraph, includedFilterPathString, excludedFilterPathString) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
const includeCache = new Map();
const excludeCache = new Map();
const pathIndexCache = new Map();
// Normalize filter paths
if (includedFilterPathString &&
!(includedFilterPathString.endsWith('/*') ||
includedFilterPathString.endsWith('/'))) {
includedFilterPathString = includedFilterPathString + '/*';
}
else if (excludedFilterPathString &&
excludedFilterPathString.endsWith('/')) {
excludedFilterPathString = excludedFilterPathString + '*';
}
const includedFilterPathList = includedFilterPathString
? includedFilterPathString.split(',')
: [];
const excludedFilterPathList = excludedFilterPathString
? excludedFilterPathString.split(',')
: [];
// check if the path is included/excluded in the filter
function checkGlob(filePath, filterPath) {
if (filePath === undefined) {
throw new Error('SourceFileMetaDataTree.checkGlob: filePath is undefined');
}
const normalizedDirectory = filePath.startsWith('./')
? filePath.substring(2)
: filePath;
const normalizedFilterPath = filterPath.startsWith('./')
? filterPath.substring(2)
: filterPath;
const includeRe = (0, glob_to_regexp_1.default)(normalizedFilterPath, { extended: true });
return (includeRe.test(normalizedDirectory) ||
includeRe.test(normalizedDirectory + '/'));
}
function pathIndexByID(pathID) {
let pathIndex = pathIndexCache.get(pathID);
if (pathIndex === undefined) {
pathIndex = self.globalIndex().getPathIndexByID(pathID);
if (pathIndex === undefined) {
throw new Error('SourceFileMetaDataTree.filter: pathIndex is undefined');
}
pathIndexCache.set(pathID, pathIndex);
}
return pathIndex;
}
// Filter function on pathIndex
function filterPaths(pathIndexObj) {
const pathIndex = pathIndexObj instanceof PathIndex_1.PathIndex
? pathIndexObj
: pathIndexByID(pathIndexObj);
if (pathIndex.id === undefined) {
throw new Error('SourceFileMetaDataTree.filter: pathIndex.id is undefined');
}
let isIncludedNode = includeCache.get(pathIndex.id);
let isExcludedNode = excludeCache.get(pathIndex.id);
if (isIncludedNode === undefined) {
if (includedFilterPathList.length === 0) {
// if no include filter is set, all are included
isIncludedNode = true;
}
else if (pathIndex.moduleIndex.identifier === '{node}') {
// always include lang_internal functions
isIncludedNode = true;
}
else {
let pathToCompare = pathIndex.identifier;
if (pathIndex.moduleIndex.identifier !== '{self}') {
// add module prefix
pathToCompare = new UnifiedPath_1.UnifiedPath('node_modules')
.join(pathIndex.moduleIndex.identifier, pathIndex.identifier)
.toString();
}
// remove ./ prefix
if (pathToCompare.startsWith('./')) {
pathToCompare = pathToCompare.substring(2);
}
isIncludedNode = false;
for (const includedFilterPath of includedFilterPathList) {
if (checkGlob(pathToCompare, includedFilterPath)) {
// only needs to be included in one filter to be included
isIncludedNode = true;
break;
}
}
}
includeCache.set(pathIndex.id, isIncludedNode);
}
if (isExcludedNode === undefined) {
if (excludedFilterPathList.length === 0) {
// if no exclude filter is set, none are excluded
isExcludedNode = false;
}
else if (pathIndex.moduleIndex.identifier === '{node}') {
// never exclude lang_internal functions
isExcludedNode = false;
}
else {
let pathToCompare = pathIndex.identifier;
if (pathIndex.moduleIndex.identifier !== '{self}') {
// add module prefix
pathToCompare = new UnifiedPath_1.UnifiedPath('node_modules')
.join(pathIndex.moduleIndex.identifier, pathIndex.identifier)
.toString();
}
// remove ./ prefix
if (pathToCompare.startsWith('./')) {
pathToCompare = pathToCompare.substring(2);
}
isExcludedNode = false;
for (const excludedFilterPath of excludedFilterPathList) {
if (checkGlob(pathToCompare, excludedFilterPath)) {
// only needs to be excluded in one filter to be excluded
isExcludedNode = true;
break;
}
}
}
excludeCache.set(pathIndex.id, isExcludedNode);
}
return isIncludedNode && !isExcludedNode;
}
function filterReferences(references) {
for (const pathID of references.keys()) {
if (!filterPaths(pathID)) {
references.delete(pathID);
}
}
}
// call the filter function
return this._filter(sourceNodeGraph, filterPaths, filterReferences);
}
_filter(sourceNodeGraph, filterPaths, filterReferences) {
const allSensorValuesToSum = [];
const allInternReferencesToMerge = [];
const allExternReferencesToMerge = [];
const allLangInternalReferencesToMerge = [];
const allContainsFilesToMerge = [];
const node = new SourceFileMetaDataTree(this.type, this.filePath, this.index);
node.headlessSensorValues = SensorValues_1.SensorValues.fromJSON(this.headlessSensorValues.toJSON());
node.linkedMetaData = this.linkedMetaData;
if (SourceFileMetaDataTree.isFileNode(this)) {
if (this.linkedMetaData === undefined) {
throw new Error('SourceFileMetaDataTree.filter: linkedMetaData is undefined');
}
const pathID = this.linkedMetaData.sourceFileMetaData.pathIndex.id;
if (pathID === undefined) {
throw new Error('SourceFileMetaDataTree.filter: pathID is undefined');
}
const max = this.linkedMetaData.sourceFileMetaData.maxSourceNodeMetaData();
const total = this.linkedMetaData.sourceFileMetaData.totalSourceNodeMetaData(sourceNodeGraph);
filterReferences(total.intern);
filterReferences(total.extern);
filterReferences(total.langInternal);
allInternReferencesToMerge.push(total.intern);
allExternReferencesToMerge.push(total.extern);
allLangInternalReferencesToMerge.push(total.langInternal);
allContainsFilesToMerge.push(new Set([pathID]));
const internSum = SensorValues_1.SensorValues.sum(...total.intern.values());
const externSum = SensorValues_1.SensorValues.sum(...total.extern.values());
const langInternalSum = SensorValues_1.SensorValues.sum(...total.langInternal.values());
// clones the total sensor values but removes the references
const ownSensorValues = total.sum.sensorValues.cloneAsIsolated();
allSensorValuesToSum.push(ownSensorValues);
node.addToAggregatedInternSourceNodeMetaDataOfTree(new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, ownSensorValues.add({
internSensorValues: internSum,
externSensorValues: externSum,
langInternalSensorValues: langInternalSum
}), undefined), max));
}
if (this.langInternalChildren.size > 0) {
const sensorValuesToSum = [];
const maxSourceNodeMetaDataToMax = [];
const internReferencesToMerge = [];
const externReferencesToMerge = [];
const langInternalReferencesToMerge = [];
const containsFilesToMerge = [];
for (const [langInternalPath, child] of this.langInternalChildren.entries()) {
const { node: filteredChild, sensorValues: filteredChildSensorValues, internReferences: filteredIntern, externReferences: filteredExtern, langInternalReferences: filteredLangInternal, containsFiles: filteredContainsFiles } = child._filter(sourceNodeGraph, filterPaths, filterReferences);
if (filteredChild) {
node.langInternalChildren.set(langInternalPath, filteredChild);
if (filteredChildSensorValues) {
sensorValuesToSum.push(filteredChildSensorValues);
}
internReferencesToMerge.push(filteredIntern);
externReferencesToMerge.push(filteredExtern);
langInternalReferencesToMerge.push(filteredLangInternal);
containsFilesToMerge.push(filteredContainsFiles);
maxSourceNodeMetaDataToMax.push(filteredChild.totalAggregatedSourceMetaData.max);
}
}
const internReferences = this._mergeReferences(...internReferencesToMerge);
const externReferences = this._mergeReferences(...externReferencesToMerge);
const langInternalReferences = this._mergeReferences(...langInternalReferencesToMerge);
const containsFilesInChildren = SetHelper_1.SetHelper.union(...containsFilesToMerge);
for (const pathID of containsFilesInChildren) {
internReferences.delete(pathID);
externReferences.delete(pathID);
langInternalReferences.delete(pathID);
}
allInternReferencesToMerge.push(internReferences);
allExternReferencesToMerge.push(externReferences);
allLangInternalReferencesToMerge.push(langInternalReferences);
node.addToAggregatedLangInternalSourceNodeMetaDataOfTree(new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, SensorValues_1.SensorValues.sum(...sensorValuesToSum, ...internReferences.values()), undefined), SourceNodeMetaData_1.SourceNodeMetaData.max(...maxSourceNodeMetaDataToMax)));
}
if (this.internChildren.size > 0) {
const sensorValuesToSum = [];
const maxSourceNodeMetaDataToMax = [];
const internReferencesToMerge = [];
const externReferencesToMerge = [];
const langInternalReferencesToMerge = [];
const containsFilesToMerge = [];
for (const [internPath, child] of this.internChildren.entries()) {
const { node: filteredChild, sensorValues: filteredChildSensorValues, internReferences: filteredIntern, externReferences: filteredExtern, langInternalReferences: filteredLangInternal, containsFiles: filteredContainsFiles } = child._filter(sourceNodeGraph, filterPaths, filterReferences);
if (filteredChild) {
node.internChildren.set(internPath, filteredChild);
if (filteredChildSensorValues) {
sensorValuesToSum.push(filteredChildSensorValues);
}
internReferencesToMerge.push(filteredIntern);
externReferencesToMerge.push(filteredExtern);
langInternalReferencesToMerge.push(filteredLangInternal);
containsFilesToMerge.push(filteredContainsFiles);
maxSourceNodeMetaDataToMax.push(filteredChild.totalAggregatedSourceMetaData.max);
}
}
const internReferences = this._mergeReferences(...internReferencesToMerge);
const externReferences = this._mergeReferences(...externReferencesToMerge);
const langInternalReferences = this._mergeReferences(...langInternalReferencesToMerge);
const containsFilesInChildren = SetHelper_1.SetHelper.union(...containsFilesToMerge);
for (const pathID of containsFilesInChildren) {
internReferences.delete(pathID);
externReferences.delete(pathID);
langInternalReferences.delete(pathID);
}
const sensorValuesSum = SensorValues_1.SensorValues.sum(...sensorValuesToSum);
const internReferencesSum = SensorValues_1.SensorValues.sum(...internReferences.values());
const externReferencesSum = SensorValues_1.SensorValues.sum(...externReferences.values());
const langInternalReferencesSum = SensorValues_1.SensorValues.sum(...langInternalReferences.values());
allInternReferencesToMerge.push(internReferences);
allExternReferencesToMerge.push(externReferences);
allLangInternalReferencesToMerge.push(langInternalReferences);
allContainsFilesToMerge.push(containsFilesInChildren);
allSensorValuesToSum.push(sensorValuesSum);
node.addToAggregatedInternSourceNodeMetaDataOfTree(new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, sensorValuesSum.add({
internSensorValues: internReferencesSum,
externSensorValues: externReferencesSum,
langInternalSensorValues: langInternalReferencesSum
}), undefined), SourceNodeMetaData_1.SourceNodeMetaData.max(...maxSourceNodeMetaDataToMax)));
}
if (this.externChildren.size > 0) {
const totalSourceNodeMetaDataToMerge = [];
for (const [moduleIdentifier, child] of this.externChildren.entries()) {
const { node: filteredChild } = child._filter(sourceNodeGraph, filterPaths, filterReferences);
if (filteredChild) {
node.externChildren.set(moduleIdentifier, filteredChild);
totalSourceNodeMetaDataToMerge.push(filteredChild.aggregatedInternSourceMetaData);
}
}
node.addToAggregatedExternSourceNodeMetaDataOfTree(SourceFileMetaData_1.AggregatedSourceNodeMetaData.join(...totalSourceNodeMetaDataToMerge));
}
const internReferences = this._mergeReferences(...allInternReferencesToMerge);
const externReferences = this._mergeReferences(...allExternReferencesToMerge);
const langInternalReferences = this._mergeReferences(...allLangInternalReferencesToMerge);
if (SourceFileMetaDataTree.isFileNode(this)) {
const survivesFilter = filterPaths(this.index);
if (!survivesFilter) {
return {
node: null,
sensorValues: undefined,
internReferences,
externReferences,
langInternalReferences,
containsFiles: SetHelper_1.SetHelper.union(...allContainsFilesToMerge)
};
}
}
if (!SourceFileMetaDataTree.isFileNode(this) &&
node.internChildren.size === 0 &&
node.langInternalChildren.size === 0 &&
node.externChildren.size === 0) {
return {
node: null,
sensorValues: undefined,
internReferences,
externReferences,
langInternalReferences,
containsFiles: SetHelper_1.SetHelper.union(...allContainsFilesToMerge)
};
}
return {
node,
sensorValues: SensorValues_1.SensorValues.sum(...allSensorValuesToSum),
internReferences,
externReferences,
langInternalReferences,
containsFiles: SetHelper_1.SetHelper.union(...allContainsFilesToMerge)
};
}
}
exports.SourceFileMetaDataTree = SourceFileMetaDataTree;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU291cmNlRmlsZU1ldGFEYXRhVHJlZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tb2RlbC9Tb3VyY2VGaWxlTWV0YURhdGFUcmVlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHVDQUF3QjtBQUV4QixvRUFBeUM7QUFFekMsMkNBQXVDO0FBQ3ZDLHlDQUFxQztBQUNyQyw2REFHNkI7QUFDN0IsNkRBQXlEO0FBS3pELDZDQUF5QztBQUN6QyxpREFBNkM7QUFDN0MsbURBQStDO0FBQy9DLHVEQUFtRDtBQUduRCwwQ0FBMkM7QUFDM0MsdURBQW1EO0FBQ25ELHlEQUFxRDtBQUNyRCxtREFBK0M7QUFDL0MsaUVBQTZEO0FBQzdELFFBQVE7QUFDUixvQ0FhaUI7QUF1QmpCLE1BQWEsc0JBRVgsU0FBUSxxQkFBUztJQTBCbEIsWUFDQyxJQUFPLEVBQ1AsUUFBdUMsRUFDdkMsS0FBc0I7UUFFdEIsS0FBSyxFQUFFLENBQUE7UUFDUCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQTtRQUNoQixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQTtRQUN4QixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQTtJQUNuQixDQUFDO0lBRUQsV0FBVztRQUNWLFFBQVEsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ25CLEtBQUssa0NBQTBCLENBQUMsSUFBSTtnQkFDbkMsT0FBUSxJQUFnRTtxQkFDdEUsS0FBSyxDQUFBO1lBQ1IsS0FBSyxrQ0FBMEIsQ0FBQyxJQUFJO2dCQUNuQyxPQUFRLElBQWdFO3FCQUN0RSxLQUFLLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQTtZQUNoQyxLQUFLLGtDQUEwQixDQUFDLFNBQVMsQ0FBQztZQUMxQyxLQUFLLGtDQUEwQixDQUFDLE1BQU07Z0JBQ3JDLE9BQ0MsSUFDQSxDQUFDLEtBQUssQ0FBQyxXQUFXLENB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