UNPKG

@typescript/analyze-trace

Version:
206 lines 9.09 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); exports.reportHighlights = void 0; const console_1 = require("console"); const fs = require("fs"); const path = require("path"); const parse_trace_file_1 = require("./parse-trace-file"); const analyze_trace_utilities_1 = require("./analyze-trace-utilities"); async function reportHighlights(tracePath, typesPath, thresholdDuration, minDuration, minPercentage, importExpressionThreshold) { const parseResult = await (0, parse_trace_file_1.parse)(tracePath, minDuration); const root = (0, analyze_trace_utilities_1.buildHotPathsTree)(parseResult, thresholdDuration, minPercentage); const result = {}; const unclosedEvents = parseResult.unclosedStack; unclosedEvents.reverse(); result["unterminatedEvents"] = undefinedIfEmpty(unclosedEvents); const hotSpots = await getHotSpots(root, importExpressionThreshold, typesPath); result["hotSpots"] = undefinedIfEmpty(hotSpots); const duplicatePackages = await getDuplicateNodeModules(parseResult.nodeModulePaths); result["duplicatePackages"] = undefinedIfEmpty(duplicatePackages); console.log(JSON.stringify(result, undefined, 2)); return !!hotSpots.length || !!duplicatePackages.length; } exports.reportHighlights = reportHighlights; async function getDuplicateNodeModules(nodeModulePaths) { const duplicates = []; for (const [packageName, packagePaths] of nodeModulePaths.entries()) { if (packagePaths.length < 2) continue; const instances = []; for (const packagePath of packagePaths) { instances.push({ path: packagePath, version: await (0, analyze_trace_utilities_1.getPackageVersion)(packagePath), }); } duplicates.push({ name: packageName, instances, }); } return duplicates; } async function getHotSpots(root, importExpressionThreshold, typesPath) { const relatedTypes = typesPath ? await (0, analyze_trace_utilities_1.getRelatedTypes)(root, typesPath, /*leafOnly*/ false) : undefined; const positionMap = await (0, analyze_trace_utilities_1.getNormalizedPositions)(root, relatedTypes); const types = typesPath ? await (0, analyze_trace_utilities_1.getTypes)(typesPath) : undefined; return await getHotSpotsWorker(root, /*currentFile*/ undefined, positionMap, relatedTypes, importExpressionThreshold); } async function getHotSpotsWorker(curr, currentFile, positionMap, relatedTypes, importExpressionThreshold) { var _a, _b; if (((_a = curr.event) === null || _a === void 0 ? void 0 : _a.cat) === "check") { const path = curr.event.args.path; if (path) { currentFile = path; } else { (0, console_1.assert)(((_b = curr.event) === null || _b === void 0 ? void 0 : _b.name) !== "checkSourceFile", "checkSourceFile should have a path"); } } const timeMs = Math.round((curr.end - curr.start) / 1000); const children = []; if (curr.children.length) { // Sort slow to fast const sortedChildren = curr.children.sort((a, b) => (b.end - b.start) - (a.end - a.start)); for (const child of sortedChildren) { children.push(...await getHotSpotsWorker(child, currentFile, positionMap, relatedTypes, importExpressionThreshold)); } } if (curr.event) { const hotFrame = await makeHotFrame(); if (hotFrame) { return [hotFrame]; } } return children; async function makeHotFrame() { const event = curr.event; switch (event.name) { // case "findSourceFile": // TODO (https://github.com/microsoft/typescript-analyze-trace/issues/2) case "emitDeclarationFileOrBundle": const dtsPath = event.args.declarationFilePath; if (!dtsPath || !fs.existsSync(dtsPath)) { return undefined; } try { const emittedImports = await (0, analyze_trace_utilities_1.getEmittedImports)(dtsPath, importExpressionThreshold); if (emittedImports.length === 0) { return undefined; } return { description: `Emit declarations file`, timeMs, path: formatPath(dtsPath), children, emittedImports, }; } catch (_a) { return undefined; } case "checkSourceFile": return { description: `Check file ${formatPath(currentFile)}`, timeMs, path: formatPath(currentFile), children, }; case "structuredTypeRelatedTo": const args = event.args; return { description: `Compare types ${args.sourceId} and ${args.targetId}`, timeMs, children, types: relatedTypes ? [getHotType(args.sourceId), getHotType(args.targetId)] : undefined, }; case "getVariancesWorker": return { description: `Determine variance of type ${event.args.id}`, timeMs, children, types: relatedTypes ? [getHotType(event.args.id)] : undefined, }; default: if (event.cat === "check" && event.args && event.args.pos && event.args.end) { const frame = { description: (0, analyze_trace_utilities_1.unmangleCamelCase)(event.name), timeMs, path: formatPath(currentFile), children: undefined, }; if (positionMap.has(currentFile)) { const updatedPos = positionMap.get(currentFile).get(event.args.pos.toString()); const updatedEnd = positionMap.get(currentFile).get(event.args.end.toString()); frame.startLine = updatedPos[0]; frame.startChar = updatedPos[1]; frame.endLine = updatedEnd[0]; frame.endChar = updatedEnd[1]; } else { frame.startOffset = event.args.pos; frame.endOffset = event.args.end; } // Hack to print the children last for readability delete frame.children; frame.children = children; return frame; } return undefined; } } function getHotType(id) { return worker(id, []); function worker(id, ancestorIds) { if (typeof id !== "number") return; const type = relatedTypes.get(id); if (!type) return undefined; if (type.location) { const path = type.location.path; if (positionMap.has(path)) { const updatedPosition = positionMap.get(path).get((0, analyze_trace_utilities_1.getLineCharMapKey)(type.location.line, type.location.char)); if (updatedPosition) { [type.location.line, type.location.char] = updatedPosition; } type.location.path = formatPath(path); } } const children = []; // If there's a cycle, suppress the children, but not the type itself if (ancestorIds.indexOf(id) < 0) { ancestorIds.push(id); for (const prop in type) { if (prop.match(/type/i)) { if (Array.isArray(type[prop])) { for (const t of type[prop]) { const child = worker(t, ancestorIds); if (child) { children.push(child); } } } else { const child = worker(type[prop], ancestorIds); if (child) { children.push(child); } } } } ancestorIds.pop(); } return { type, children }; } } } function formatPath(p) { return path.normalize(p); } function undefinedIfEmpty(arr) { return arr.length ? arr : undefined; } //# sourceMappingURL=print-trace-analysis-json.js.map