UNPKG

@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

448 lines 35.8 kB
"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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExternalResourceHelper = void 0; const fs = __importStar(require("fs")); const LoggerHelper_1 = require("./LoggerHelper"); const PermissionHelper_1 = require("./PermissionHelper"); const TypescriptParser_1 = require("./TypescriptParser"); const GitHelper_1 = require("./GitHelper"); const InspectorSessionHelper_1 = require("./InspectorSessionHelper"); const SourceMap_1 = require("../model/SourceMap"); const UnifiedPath_1 = require("../system/UnifiedPath"); const NodeModule_1 = require("../model/NodeModule"); class ExternalResourceHelper { constructor(rootDir) { this._boundInspectorNotification = this.inspectorNotification.bind(this); this._rootDir = rootDir; this._frozen = false; this.fileInfoPerScriptID = new Map(); this.fileInfoPerPath = new Map(); this.nodeModules = new Map(); } get rootDir() { return this._rootDir; } get isFrozen() { return this._frozen; } get scriptIDs() { return Array.from(this.fileInfoPerScriptID.keys()); } get loadedFilePaths() { return Array.from(this.fileInfoPerPath.keys()); } get uncommittedFiles() { return this._uncommittedFiles; } trackUncommittedFiles(rootDir, globalIndex) { var _a; let uncommittedFiles = this._uncommittedFiles; if (uncommittedFiles === undefined) { uncommittedFiles = GitHelper_1.GitHelper.uncommittedFiles(); } if (uncommittedFiles === null) { // git is unavailable this._uncommittedFiles = null; return null; } const trackedUncommittedFiles = []; for (const file of uncommittedFiles) { const uncommittedFile = rootDir.pathTo(file).toString(); // track only uncommitted files that are part of the global index const pathIndex = (_a = globalIndex .getModuleIndex('get')) === null || _a === void 0 ? void 0 : _a.getFilePathIndex('get', uncommittedFile); if (pathIndex === undefined) { continue; } // mark the file as uncommitted in the global index pathIndex.containsUncommittedChanges = true; // add the file to the uncommitted files list trackedUncommittedFiles.push(uncommittedFile); // also mark the file as uncommitted in the file info const fileInfo = this.fileInfoFromPath(uncommittedFile, rootDir.join(uncommittedFile)); if (fileInfo !== null) { fileInfo.cucc = true; } } this._uncommittedFiles = trackedUncommittedFiles; return trackedUncommittedFiles.length > 0; } connect() { return __awaiter(this, void 0, void 0, function* () { // wait for debugger to be enabled yield new Promise((resolve) => { InspectorSessionHelper_1.InspectorSessionHelper.session.post('Debugger.enable', resolve); }); }); } storeToFile(filePath, kind) { switch (kind) { 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; } } static loadFromFile(rootDir, filePath) { if (!fs.existsSync(filePath.toPlatformString())) { return undefined; } return ExternalResourceHelper.fromJSON(rootDir, fs.readFileSync(filePath.toPlatformString()).toString()); } toJSON() { const fileInfoPerScriptID = {}; for (const [key, value] of this.fileInfoPerScriptID.entries()) { if (value === null) { fileInfoPerScriptID[key] = null; continue; } const fileInfo = { sourceCode: value.sourceCode }; if (value.cucc !== undefined) { fileInfo.cucc = value.cucc; } fileInfoPerScriptID[key] = fileInfo; } const fileInfoPerPath = {}; for (const [key, value] of this.fileInfoPerPath.entries()) { if (value === null) { fileInfoPerPath[key] = null; continue; } const fileInfo = { sourceCode: value.sourceCode }; if (value.cucc !== undefined) { fileInfo.cucc = value.cucc; } fileInfoPerPath[key] = fileInfo; } const nodeModules = {}; for (const [key, value] of this.nodeModules.entries()) { if (value === null) { nodeModules[key] = null; continue; } nodeModules[key] = value.toJSON(); } return { fileInfoPerScriptID, fileInfoPerPath, nodeModules }; } static fromJSON(rootDir, json) { let data; if (typeof json === 'string') { data = JSON.parse(json); } else { data = json; } const result = new ExternalResourceHelper(rootDir); result._uncommittedFiles = []; for (const [key, value] of Object.entries(data.fileInfoPerScriptID)) { let fileInfo = null; if (value !== null) { fileInfo = { sourceCode: value.sourceCode }; if (value.cucc !== undefined) { fileInfo.cucc = value.cucc; } } result.fileInfoPerScriptID.set(key, fileInfo); } for (const [key, value] of Object.entries(data.fileInfoPerPath)) { let fileInfo = null; if (value !== null) { fileInfo = { sourceCode: value.sourceCode }; if (value.cucc !== undefined) { fileInfo.cucc = value.cucc; if (value.cucc === true) { result._uncommittedFiles.push(key); } } } result.fileInfoPerPath.set(key, fileInfo); } for (const [key, value] of Object.entries(data.nodeModules)) { result.nodeModules.set(key, value !== null ? NodeModule_1.NodeModule.fromJSON(value) : null); } // freeze the object to prevent further modifications result._frozen = true; return result; } inspectorNotification(message) { return __awaiter(this, void 0, void 0, function* () { if (message.method === 'Debugger.scriptParsed') { const params = message.params; // store source code for later use yield this.fileInfoFromScriptID(params.scriptId); } }); } listen() { return __awaiter(this, void 0, void 0, function* () { yield InspectorSessionHelper_1.InspectorSessionHelper.session.on('inspectorNotification', this._boundInspectorNotification); }); } disconnect() { return __awaiter(this, void 0, void 0, function* () { yield new Promise((resolve) => { InspectorSessionHelper_1.InspectorSessionHelper.session.post('Debugger.disable', resolve); }); InspectorSessionHelper_1.InspectorSessionHelper.session.removeListener('inspectorNotification', this._boundInspectorNotification); }); } fillSourceMapsFromCPUProfile(profile) { return __awaiter(this, void 0, void 0, function* () { const scriptMap = new Map(); for (const location of profile.nodes) { const scriptId = location.callFrame.scriptId.toString(); if (scriptMap.has(scriptId)) { continue; } scriptMap.set(scriptId, location.callFrame.url); } const promises = []; for (const [scriptId, filePath] of scriptMap) { promises.push(this.sourceMapFromScriptID(scriptId, new UnifiedPath_1.UnifiedPath(filePath))); } yield Promise.all(promises); }); } fileInfoFromPath(relativePath, filePath) { const relativePathString = typeof relativePath === 'string' ? relativePath : relativePath.toString(); const filePathPlatformString = typeof filePath === 'string' ? filePath : filePath.toPlatformString(); let fileInfo = this.fileInfoPerPath.get(relativePathString); if (fileInfo !== undefined) { return fileInfo; } if (this.isFrozen) { throw new Error('ExternalResourceHelper.fileInfoFromPath: Cannot load file while frozen' + 'Tried to access: ' + relativePathString); } if (fs.existsSync(filePathPlatformString) && fs.statSync(filePathPlatformString).isFile()) { fileInfo = { sourceCode: fs.readFileSync(filePathPlatformString).toString() }; } else { fileInfo = null; } this.fileInfoPerPath.set(relativePathString, fileInfo); return fileInfo; } sourceCodeFromPath(relativePath, filePath) { const fileInfo = this.fileInfoFromPath(relativePath, filePath); if (fileInfo === null) { return null; } return fileInfo.sourceCode; } sourceMapFromPath(relativePath, filePath) { return __awaiter(this, void 0, void 0, function* () { const fileInfo = this.fileInfoFromPath(relativePath, filePath); if (fileInfo === null) { return null; } if (fileInfo.sourceMap !== undefined) { return fileInfo.sourceMap; } let sourceMap = SourceMap_1.SourceMap.fromCompiledJSString(filePath, fileInfo.sourceCode); if (sourceMap !== null) { if (sourceMap.type === 'redirect') { sourceMap = yield this.sourceMapFromPath(this.rootDir.pathTo(sourceMap.sourceMapLocation), sourceMap.sourceMapLocation); } } fileInfo.sourceMap = sourceMap; return fileInfo.sourceMap; }); } parseFile(relativePath, filePath) { const fileInfo = this.fileInfoFromPath(relativePath, filePath); if (fileInfo === null) { return null; } return TypescriptParser_1.TypescriptParser.parseSource(filePath, fileInfo.sourceCode); } fileInfoFromScriptID(scriptID, filePath) { return __awaiter(this, void 0, void 0, function* () { if (scriptID === '0') { return null; } let fileInfo = this.fileInfoPerScriptID.get(scriptID); if (fileInfo !== undefined) { return fileInfo; } if (this.isFrozen) { throw new Error('ExternalResourceHelper.fileInfoFromScriptID: Cannot script from inspector while frozen\n' + 'Tried to access: ' + scriptID); } const result = yield new Promise((resolve) => { InspectorSessionHelper_1.InspectorSessionHelper.session.post('Debugger.getScriptSource', { scriptId: scriptID }, (err, args) => { if (err) { resolve({ source: '', err }); } else { resolve({ source: args.scriptSource }); } }); }); if (result.err) { LoggerHelper_1.LoggerHelper.error('Error getting script source', result.err, { scriptId: scriptID, filePath }); throw result.err; } fileInfo = { sourceCode: result.source }; this.fileInfoPerScriptID.set(scriptID, fileInfo); return fileInfo; }); } sourceCodeFromScriptID(scriptID) { return __awaiter(this, void 0, void 0, function* () { const fileInfo = yield this.fileInfoFromScriptID(scriptID); if (fileInfo === null) { return null; } return fileInfo.sourceCode; }); } sourceMapFromScriptID(scriptID, filePath) { return __awaiter(this, void 0, void 0, function* () { const fileInfo = yield this.fileInfoFromScriptID(scriptID, filePath); if (fileInfo === null || fileInfo.sourceMap === null) { return null; } if (fileInfo.sourceMap !== undefined) { return fileInfo.sourceMap; } let sourceMap = SourceMap_1.SourceMap.fromCompiledJSString(filePath, fileInfo.sourceCode); if (sourceMap !== null) { if (sourceMap.type === 'redirect') { const sourceMapCode = yield this.sourceCodeFromPath(this.rootDir.pathTo(sourceMap.sourceMapLocation), sourceMap.sourceMapLocation); sourceMap = sourceMapCode === null ? null : SourceMap_1.SourceMap.fromJSON(sourceMapCode); } } fileInfo.sourceMap = sourceMap; return fileInfo.sourceMap; }); } nodeModuleFromPath(relativeNodeModulePath) { let nodeModule = this.nodeModules.get(relativeNodeModulePath.toString()); if (nodeModule !== undefined) { return nodeModule; } if (this.isFrozen) { throw new Error('ExternalResourceHelper.nodeModuleFromPath: Cannot load node modules while frozen\n' + 'Tried to access: ' + relativeNodeModulePath.toString()); } nodeModule = NodeModule_1.NodeModule.fromNodeModulePath(this.rootDir.join(relativeNodeModulePath)) || null; this.nodeModules.set(relativeNodeModulePath.toString(), nodeModule); return nodeModule; } replaceSourceMapByScriptID(scriptID, newSourceMap) { return __awaiter(this, void 0, void 0, function* () { const fileInfo = yield this.fileInfoFromScriptID(scriptID); if (fileInfo === null) { throw new Error(`No source code found for scriptID ${scriptID}`); } const result = SourceMap_1.SourceMap.base64StringCompiledJSString(fileInfo.sourceCode); if (result === null || result.base64 === undefined || result.base64 === null) { throw new Error(`No source map found for scriptID ${scriptID}`); } const oldBase64String = result.base64; const newBase64String = newSourceMap.toBase64String(); if (oldBase64String === newBase64String) { return; } fileInfo.sourceCode = fileInfo.sourceCode.replace(oldBase64String, newBase64String); fileInfo.sourceMap = newSourceMap; }); } replaceSourceMapByLoadedFile(relativePath, newSourceMap) { return __awaiter(this, void 0, void 0, function* () { const fileInfo = this.fileInfoFromPath(relativePath, relativePath); if (fileInfo === null) { throw new Error(`No source code found for relativePath ${relativePath.toString()}`); } const result = SourceMap_1.SourceMap.base64StringCompiledJSString(fileInfo.sourceCode); if (result === null || result.base64 === undefined || result.base64 === null) { throw new Error(`No source map found for relativePath ${relativePath.toString()}`); } const oldBase64String = result.base64; const newBase64String = newSourceMap.toBase64String(); if (oldBase64String === newBase64String) { return; } fileInfo.sourceCode = fileInfo.sourceCode.replace(oldBase64String, newBase64String); fileInfo.sourceMap = newSourceMap; }); } } exports.ExternalResourceHelper = ExternalResourceHelper; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXh0ZXJuYWxSZXNvdXJjZUhlbHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9oZWxwZXIvRXh0ZXJuYWxSZXNvdXJjZUhlbHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBd0I7QUFHeEIsaURBQTZDO0FBQzdDLHlEQUFxRDtBQUNyRCx5REFBcUQ7QUFDckQsMkNBQXVDO0FBQ3ZDLHFFQUFpRTtBQUdqRSxrREFBaUU7QUFDakUsdURBQW1EO0FBQ25ELG9EQUFnRDtBQW1CaEQsTUFBYSxzQkFBc0I7SUEwQmxDLFlBQVksT0FBb0I7UUEyT3hCLGdDQUEyQixHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUExTzFFLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFBO1FBQ3ZCLElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFBO1FBQ3BCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBQ3BDLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUNoQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUE7SUFDN0IsQ0FBQztJQUVELElBQUksT0FBTztRQUNWLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQTtJQUNyQixDQUFDO0lBRUQsSUFBSSxRQUFRO1FBQ1gsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3BCLENBQUM7SUFFRCxJQUFJLFNBQVM7UUFDWixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxDQUFDLENBQUE7SUFDbkQsQ0FBQztJQUVELElBQUksZUFBZTtRQUNsQixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFD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