@densetsuuu/docteur 0.1.1-beta.3 → 0.1.1-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/src/cli/commands/diagnose.js +3 -3
- package/build/src/cli/commands/xray.js +3 -3
- package/build/src/profiler/collector.d.ts +1 -1
- package/build/src/profiler/collector.js +1 -1
- package/build/src/profiler/hooks.d.ts +4 -24
- package/build/src/profiler/hooks.js +6 -6
- package/build/src/profiler/loader.js +34 -34
- package/build/src/profiler/profiler.d.ts +1 -1
- package/build/src/profiler/profiler.js +2 -2
- package/build/src/profiler/reporters/base_reporter.d.ts +1 -1
- package/build/src/profiler/reporters/console_reporter.js +2 -2
- package/build/src/profiler/reporters/format.d.ts +2 -8
- package/build/src/profiler/reporters/format.js +1 -1
- package/build/src/profiler/reporters/tui_reporter.js +1 -1
- package/build/src/{profiler/registries → registries}/categories.d.ts +1 -1
- package/build/src/xray/components/ListView.js +1 -1
- package/build/src/xray/components/ModuleView.js +1 -1
- package/build/src/xray/components/ProviderListView.d.ts +1 -1
- package/build/src/xray/components/ProviderListView.js +1 -1
- package/build/src/xray/components/ProviderView.d.ts +1 -1
- package/build/src/xray/components/ProviderView.js +1 -1
- package/build/src/xray/components/XRayApp.d.ts +1 -1
- package/build/src/xray/tree.d.ts +2 -2
- package/build/src/xray/tree.js +2 -2
- package/package.json +21 -3
- /package/build/src/{profiler/registries → registries}/categories.js +0 -0
- /package/build/src/{profiler/registries → registries}/index.d.ts +0 -0
- /package/build/src/{profiler/registries → registries}/index.js +0 -0
- /package/build/src/{profiler/registries → registries}/symbols.d.ts +0 -0
- /package/build/src/{profiler/registries → registries}/symbols.js +0 -0
package/README.md
CHANGED
package/build/index.d.ts
CHANGED
|
@@ -20,4 +20,4 @@ export { colorDuration, createBar, formatDuration, getCategoryIcon, getEffective
|
|
|
20
20
|
/**
|
|
21
21
|
* Export registries for customization
|
|
22
22
|
*/
|
|
23
|
-
export { categories, fileIcons, symbols, type CategoryDefinition, type SymbolKey, } from './src/
|
|
23
|
+
export { categories, fileIcons, symbols, type CategoryDefinition, type SymbolKey, } from './src/registries/index.js';
|
package/build/index.js
CHANGED
|
@@ -20,4 +20,4 @@ export { colorDuration, createBar, formatDuration, getCategoryIcon, getEffective
|
|
|
20
20
|
/**
|
|
21
21
|
* Export registries for customization
|
|
22
22
|
*/
|
|
23
|
-
export { categories, fileIcons, symbols, } from './src/
|
|
23
|
+
export { categories, fileIcons, symbols, } from './src/registries/index.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
|
-
import { isAdonisProject, profile } from '
|
|
3
|
-
import { ConsoleReporter } from '
|
|
4
|
-
import { ui } from '
|
|
2
|
+
import { isAdonisProject, profile } from '#profiler/profiler';
|
|
3
|
+
import { ConsoleReporter } from '#profiler/reporters/console_reporter';
|
|
4
|
+
import { ui } from '#profiler/reporters/format';
|
|
5
5
|
export const diagnoseCommand = defineCommand({
|
|
6
6
|
meta: {
|
|
7
7
|
name: 'diagnose',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineCommand } from 'citty';
|
|
2
|
-
import { isAdonisProject, profile } from '
|
|
3
|
-
import { TuiReporter } from '
|
|
4
|
-
import { ui } from '
|
|
2
|
+
import { isAdonisProject, profile } from '#profiler/profiler';
|
|
3
|
+
import { TuiReporter } from '#profiler/reporters/tui_reporter';
|
|
4
|
+
import { ui } from '#profiler/reporters/format';
|
|
5
5
|
export const xrayCommand = defineCommand({
|
|
6
6
|
meta: {
|
|
7
7
|
name: 'xray',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppFileGroup, ModuleTiming, ProfileResult, ProfileSummary, ProviderTiming, ResolvedConfig } from '
|
|
1
|
+
import type { AppFileGroup, ModuleTiming, ProfileResult, ProfileSummary, ProviderTiming, ResolvedConfig } from '#types';
|
|
2
2
|
export interface PackageGroup {
|
|
3
3
|
name: string;
|
|
4
4
|
totalTime: number;
|
|
@@ -1,27 +1,7 @@
|
|
|
1
|
+
import type { InitializeHook, LoadHook, ResolveHook } from 'node:module';
|
|
1
2
|
import type { MessagePort } from 'node:worker_threads';
|
|
2
|
-
|
|
3
|
-
parentURL?: string;
|
|
4
|
-
}) => Promise<{
|
|
5
|
-
url: string;
|
|
6
|
-
}>;
|
|
7
|
-
type LoadFn = (url: string, context?: {
|
|
8
|
-
format?: string;
|
|
9
|
-
}) => Promise<{
|
|
10
|
-
format: string;
|
|
11
|
-
source: string | ArrayBuffer | SharedArrayBuffer;
|
|
12
|
-
}>;
|
|
13
|
-
export declare function initialize(data: {
|
|
3
|
+
export declare const initialize: InitializeHook<{
|
|
14
4
|
port: MessagePort;
|
|
15
|
-
}): void;
|
|
16
|
-
export declare function resolve(specifier: string, context: {
|
|
17
|
-
parentURL?: string;
|
|
18
|
-
}, next: ResolveFn): Promise<{
|
|
19
|
-
url: string;
|
|
20
|
-
}>;
|
|
21
|
-
export declare function load(url: string, context: {
|
|
22
|
-
format?: string;
|
|
23
|
-
}, next: LoadFn): Promise<{
|
|
24
|
-
format: string;
|
|
25
|
-
source: string | ArrayBuffer | SharedArrayBuffer;
|
|
26
5
|
}>;
|
|
27
|
-
export
|
|
6
|
+
export declare const resolve: ResolveHook;
|
|
7
|
+
export declare const load: LoadHook;
|
|
@@ -10,17 +10,17 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { performance } from 'node:perf_hooks';
|
|
12
12
|
let port;
|
|
13
|
-
export
|
|
13
|
+
export const initialize = (data) => {
|
|
14
14
|
port = data.port;
|
|
15
|
-
}
|
|
16
|
-
export async
|
|
15
|
+
};
|
|
16
|
+
export const resolve = async (specifier, context, next) => {
|
|
17
17
|
const result = await next(specifier, context);
|
|
18
18
|
if (context.parentURL && result.url.startsWith('file://')) {
|
|
19
19
|
port.postMessage({ type: 'parent', child: result.url, parent: context.parentURL });
|
|
20
20
|
}
|
|
21
21
|
return result;
|
|
22
|
-
}
|
|
23
|
-
export async
|
|
22
|
+
};
|
|
23
|
+
export const load = async (url, context, next) => {
|
|
24
24
|
if (!url.startsWith('file://')) {
|
|
25
25
|
return next(url, context);
|
|
26
26
|
}
|
|
@@ -30,4 +30,4 @@ export async function load(url, context, next) {
|
|
|
30
30
|
port.postMessage({ type: 'timing', url, loadTime: performance.now() - start });
|
|
31
31
|
}
|
|
32
32
|
return result;
|
|
33
|
-
}
|
|
33
|
+
};
|
|
@@ -13,14 +13,11 @@ import { performance } from 'node:perf_hooks';
|
|
|
13
13
|
import { MessageChannel } from 'node:worker_threads';
|
|
14
14
|
const require = createRequire(join(process.cwd(), 'node_modules', '_'));
|
|
15
15
|
const { tracingChannels } = require('@adonisjs/application');
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Module timing data collected via ESM hooks
|
|
18
|
+
*/
|
|
17
19
|
const parents = new Map();
|
|
18
20
|
const loadTimes = new Map();
|
|
19
|
-
// Provider timing data
|
|
20
|
-
const providerPhases = new Map();
|
|
21
|
-
const providerStarts = new Map();
|
|
22
|
-
const asyncCalls = new Set();
|
|
23
|
-
// Set up message channel for hooks
|
|
24
21
|
const { port1, port2 } = new MessageChannel();
|
|
25
22
|
port1.unref();
|
|
26
23
|
port1.on('message', (msg) => {
|
|
@@ -34,54 +31,57 @@ register('./hooks.js', {
|
|
|
34
31
|
data: { port: port2 },
|
|
35
32
|
transferList: [port2],
|
|
36
33
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Provider lifecycle timing via tracing channels.
|
|
36
|
+
*
|
|
37
|
+
* Tracing channels emit: start → end (sync) or start → end → asyncStart → asyncEnd (async).
|
|
38
|
+
* We defer sync recording with setTimeout so asyncStart can claim the phase first.
|
|
39
|
+
*/
|
|
40
|
+
const providerPhases = new Map();
|
|
41
|
+
const starts = new Map();
|
|
42
|
+
const asyncPhases = new Set();
|
|
43
|
+
function name(msg) {
|
|
41
44
|
return msg.provider.constructor.name;
|
|
42
45
|
}
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
const start = providerStarts.get(key);
|
|
46
|
+
function record(provider, phase, endTime) {
|
|
47
|
+
const start = starts.get(`${provider}:${phase}`);
|
|
46
48
|
if (start === undefined)
|
|
47
49
|
return;
|
|
48
|
-
const phases = providerPhases.get(
|
|
50
|
+
const phases = providerPhases.get(provider) ?? {};
|
|
49
51
|
phases[phase] = endTime - start;
|
|
50
|
-
providerPhases.set(
|
|
51
|
-
|
|
52
|
+
providerPhases.set(provider, phases);
|
|
53
|
+
starts.delete(`${provider}:${phase}`);
|
|
52
54
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
const phases = ['register', 'boot', 'start', 'ready', 'shutdown'];
|
|
56
|
+
for (const phase of phases) {
|
|
57
|
+
const channelKey = `provider${phase[0].toUpperCase()}${phase.slice(1)}`;
|
|
58
|
+
tracingChannels[channelKey].subscribe({
|
|
55
59
|
start(msg) {
|
|
56
|
-
|
|
60
|
+
starts.set(`${name(msg)}:${phase}`, performance.now());
|
|
57
61
|
},
|
|
58
62
|
end(msg) {
|
|
59
|
-
const
|
|
60
|
-
const key = `${name}:${phase}`;
|
|
63
|
+
const provider = name(msg);
|
|
61
64
|
const endTime = performance.now();
|
|
62
|
-
|
|
65
|
+
const key = `${provider}:${phase}`;
|
|
63
66
|
setTimeout(() => {
|
|
64
|
-
if (!
|
|
65
|
-
|
|
67
|
+
if (!asyncPhases.has(key))
|
|
68
|
+
record(provider, phase, endTime);
|
|
66
69
|
}, 0);
|
|
67
70
|
},
|
|
68
71
|
asyncStart(msg) {
|
|
69
|
-
|
|
72
|
+
asyncPhases.add(`${name(msg)}:${phase}`);
|
|
70
73
|
},
|
|
71
74
|
asyncEnd(msg) {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
const provider = name(msg);
|
|
76
|
+
record(provider, phase, performance.now());
|
|
77
|
+
asyncPhases.delete(`${provider}:${phase}`);
|
|
75
78
|
},
|
|
76
79
|
error() { },
|
|
77
80
|
});
|
|
78
81
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
subscribePhase(tracingChannels.providerReady, 'ready');
|
|
83
|
-
subscribePhase(tracingChannels.providerShutdown, 'shutdown');
|
|
84
|
-
// Send results to parent process when requested
|
|
82
|
+
/**
|
|
83
|
+
* IPC: send collected results to parent process
|
|
84
|
+
*/
|
|
85
85
|
if (process.send) {
|
|
86
86
|
process.on('message', (msg) => {
|
|
87
87
|
if (msg.type !== 'getResults')
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
|
|
|
9
9
|
*/
|
|
10
10
|
import { fork } from 'node:child_process';
|
|
11
|
-
import { join } from 'node:path';
|
|
12
11
|
import { existsSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
13
|
import { ProfileCollector } from './collector.js';
|
|
14
|
-
import { simplifyUrl } from '
|
|
14
|
+
import { simplifyUrl } from '#profiler/reporters/format';
|
|
15
15
|
const TIMEOUT_MS = 30_000;
|
|
16
16
|
export function findLoaderPath() {
|
|
17
17
|
return import.meta.resolve('@densetsuuu/docteur/profiler/loader');
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
| Renders profiling results to the terminal using @poppinss/cliui.
|
|
7
7
|
|
|
|
8
8
|
*/
|
|
9
|
-
import { ProfileCollector } from '
|
|
10
|
-
import { symbols } from '
|
|
9
|
+
import { ProfileCollector } from '#profiler/collector';
|
|
10
|
+
import { symbols } from '#registries/index';
|
|
11
11
|
import { colorDuration, createBar, formatDuration, getCategoryIcon, getEffectiveTime, simplifyUrl, ui, } from './format.js';
|
|
12
12
|
export class ConsoleReporter {
|
|
13
13
|
/**
|
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
import type { AppFileCategory, ModuleTiming } from '
|
|
1
|
+
import type { AppFileCategory, ModuleTiming } from '#types';
|
|
2
2
|
/**
|
|
3
3
|
* Shared UI instance for consistent styling
|
|
4
4
|
*/
|
|
5
5
|
export declare const ui: {
|
|
6
6
|
colors: import("@poppinss/colors/types").Colors;
|
|
7
7
|
logger: import("@poppinss/cliui").Logger;
|
|
8
|
-
table: (tableOptions
|
|
9
|
-
/**
|
|
10
|
-
* Colors a duration based on how slow it is
|
|
11
|
-
*/
|
|
12
|
-
? /**
|
|
13
|
-
* Colors a duration based on how slow it is
|
|
14
|
-
*/: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
|
|
8
|
+
table: (tableOptions?: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
|
|
15
9
|
tasks: (tasksOptions?: Partial<import("@poppinss/cliui/types").TaskManagerOptions>) => import("@poppinss/cliui").TaskManager;
|
|
16
10
|
steps: () => import("@poppinss/cliui").Steps;
|
|
17
11
|
icons: {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import React from 'react';
|
|
11
11
|
import { render } from 'ink';
|
|
12
|
-
import { XRayApp } from '
|
|
12
|
+
import { XRayApp } from '#xray/components/XRayApp';
|
|
13
13
|
export class TuiReporter {
|
|
14
14
|
/**
|
|
15
15
|
* Renders an interactive TUI report using the XRay explorer.
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import SelectInput from 'ink-select-input';
|
|
4
4
|
import { formatDuration, getEffectiveTime, getFileIcon, getTimeColor, isDependency, } from '../tree.js';
|
|
5
|
-
import { symbols } from '
|
|
5
|
+
import { symbols } from '#registries/index';
|
|
6
6
|
function ItemComponent({ isSelected = false, label, timeStr, timeColor, fileIcon, displayName, }) {
|
|
7
7
|
// Spacer
|
|
8
8
|
if (!label) {
|
|
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
|
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import SelectInput from 'ink-select-input';
|
|
5
5
|
import { formatDuration, getEffectiveTime, getImportChain, getFileIcon, getSourceIcon, getTimeColor, isDependency, } from '../tree.js';
|
|
6
|
-
import { symbols } from '
|
|
6
|
+
import { symbols } from '#registries/index';
|
|
7
7
|
function ItemComponent({ isSelected = false, label }) {
|
|
8
8
|
if (!label) {
|
|
9
9
|
return _jsx(Text, { children: " " });
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import SelectInput from 'ink-select-input';
|
|
4
4
|
import { formatDuration, getTimeColor } from '../tree.js';
|
|
5
|
-
import { symbols } from '
|
|
5
|
+
import { symbols } from '#registries/index';
|
|
6
6
|
function ItemComponent({ isSelected = false, timeStr, timeColor, name, label }) {
|
|
7
7
|
// Spacer
|
|
8
8
|
if (!label) {
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import SelectInput from 'ink-select-input';
|
|
4
4
|
import { formatDuration, getTimeColor } from '../tree.js';
|
|
5
|
-
import { symbols } from '
|
|
5
|
+
import { symbols } from '#registries/index';
|
|
6
6
|
function Bar({ value, max, width = 30 }) {
|
|
7
7
|
const ratio = max > 0 ? Math.min(value / max, 1) : 0;
|
|
8
8
|
const filled = Math.round(ratio * width);
|
package/build/src/xray/tree.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ModuleTiming } from '
|
|
2
|
-
import { formatDuration, getEffectiveTime } from '
|
|
1
|
+
import type { ModuleTiming } from '#types';
|
|
2
|
+
import { formatDuration, getEffectiveTime } from '#profiler/reporters/format';
|
|
3
3
|
export interface ModuleNode {
|
|
4
4
|
timing: ModuleTiming;
|
|
5
5
|
displayName: string;
|
package/build/src/xray/tree.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
| Provides utilities for traversing and displaying the tree.
|
|
8
8
|
|
|
|
9
9
|
*/
|
|
10
|
-
import { formatDuration, getEffectiveTime, simplifyUrl } from '
|
|
11
|
-
import { fileIcons, symbols } from '
|
|
10
|
+
import { formatDuration, getEffectiveTime, simplifyUrl } from '#profiler/reporters/format';
|
|
11
|
+
import { fileIcons, symbols } from '#registries/index';
|
|
12
12
|
export function buildDependencyTree(modules, cwd) {
|
|
13
13
|
const nodeMap = new Map();
|
|
14
14
|
const time = (n) => getEffectiveTime(n.timing);
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@densetsuuu/docteur",
|
|
3
3
|
"description": "AdonisJS cold start profiler - analyze and optimize your application boot time",
|
|
4
|
-
"version": "0.1.1-beta.
|
|
4
|
+
"version": "0.1.1-beta.5",
|
|
5
5
|
"engines": {
|
|
6
|
-
"node": ">=
|
|
6
|
+
"node": ">=22.0.0"
|
|
7
7
|
},
|
|
8
8
|
"main": "./build/index.js",
|
|
9
9
|
"types": "./build/index.d.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"typecheck": "tsc --noEmit",
|
|
31
31
|
"lint": "eslint .",
|
|
32
32
|
"format": "prettier --write .",
|
|
33
|
-
"quick:test": "node --import=./tsnode.esm.js --enable-source-maps bin/test.ts",
|
|
33
|
+
"quick:test": "node --conditions=development --import=./tsnode.esm.js --enable-source-maps bin/test.ts",
|
|
34
34
|
"pretest": "npm run lint",
|
|
35
35
|
"test": "c8 npm run quick:test",
|
|
36
36
|
"prebuild": "npm run lint && npm run clean",
|
|
@@ -92,6 +92,24 @@
|
|
|
92
92
|
"optional": true
|
|
93
93
|
}
|
|
94
94
|
},
|
|
95
|
+
"imports": {
|
|
96
|
+
"#registries/*": {
|
|
97
|
+
"development": "./src/registries/*.js",
|
|
98
|
+
"default": "./build/src/registries/*.js"
|
|
99
|
+
},
|
|
100
|
+
"#types": {
|
|
101
|
+
"development": "./src/types.js",
|
|
102
|
+
"default": "./build/src/types.js"
|
|
103
|
+
},
|
|
104
|
+
"#profiler/*": {
|
|
105
|
+
"development": "./src/profiler/*.js",
|
|
106
|
+
"default": "./build/src/profiler/*.js"
|
|
107
|
+
},
|
|
108
|
+
"#xray/*": {
|
|
109
|
+
"development": "./src/xray/*.js",
|
|
110
|
+
"default": "./build/src/xray/*.js"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
95
113
|
"publishConfig": {
|
|
96
114
|
"access": "public",
|
|
97
115
|
"tag": "latest"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|