@memlab/cli 1.0.24 → 1.0.25

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.
Files changed (41) hide show
  1. package/dist/BaseCommand.d.ts +3 -3
  2. package/dist/BaseCommand.js +5 -1
  3. package/dist/Dispatcher.js +6 -0
  4. package/dist/commands/MemLabRunCommand.d.ts +2 -2
  5. package/dist/commands/RunMeasureCommand.d.ts +2 -2
  6. package/dist/commands/RunMeasureCommand.js +2 -0
  7. package/dist/commands/WarmupAppCommand.d.ts +2 -2
  8. package/dist/commands/WarmupAppCommand.js +2 -0
  9. package/dist/commands/heap/CheckLeakCommand.d.ts +2 -1
  10. package/dist/commands/heap/CheckLeakCommand.js +44 -5
  11. package/dist/commands/heap/DiffLeakCommand.d.ts +13 -1
  12. package/dist/commands/heap/DiffLeakCommand.js +42 -12
  13. package/dist/commands/heap/GetRetainerTraceCommand.d.ts +2 -2
  14. package/dist/commands/heap/HeapAnalysisCommand.d.ts +2 -2
  15. package/dist/commands/heap/interactive/InteractiveHeapCommand.d.ts +2 -2
  16. package/dist/commands/heap/interactive/InteractiveHeapExploreCommand.d.ts +2 -2
  17. package/dist/commands/heap/interactive/ui-components/HeapViewUtils.d.ts +2 -0
  18. package/dist/commands/heap/interactive/ui-components/HeapViewUtils.js +25 -21
  19. package/dist/commands/heap/interactive/ui-components/ListComponent.js +1 -1
  20. package/dist/commands/helper/GenerateCLIDocCommand.js +10 -7
  21. package/dist/commands/helper/HelperCommand.d.ts +7 -4
  22. package/dist/commands/helper/HelperCommand.js +17 -13
  23. package/dist/commands/helper/lib/DocUtils.d.ts +19 -0
  24. package/dist/commands/helper/lib/DocUtils.js +39 -0
  25. package/dist/commands/snapshot/TakeSnapshotCommand.d.ts +2 -2
  26. package/dist/commands/snapshot/TakeSnapshotCommand.js +2 -0
  27. package/dist/commands/snapshot/WarmupAndSnapshotCommand.d.ts +3 -1
  28. package/dist/commands/snapshot/WarmupAndSnapshotCommand.js +23 -0
  29. package/dist/options/SetMaxClusterSampleSizeOption.d.ts +19 -0
  30. package/dist/options/SetMaxClusterSampleSizeOption.js +49 -0
  31. package/dist/options/e2e/SetChromiumBinaryOption.d.ts +18 -0
  32. package/dist/options/e2e/SetChromiumBinaryOption.js +43 -0
  33. package/dist/options/experiment/SetControlWorkDirOption.d.ts +3 -3
  34. package/dist/options/experiment/SetControlWorkDirOption.js +1 -1
  35. package/dist/options/heap/SetTraceContainsFilterOption.d.ts +18 -0
  36. package/dist/options/heap/SetTraceContainsFilterOption.js +42 -0
  37. package/dist/options/heap/TraceAllObjectsOption.d.ts +4 -2
  38. package/dist/options/heap/TraceAllObjectsOption.js +26 -4
  39. package/dist/options/lib/OptionConstant.d.ts +6 -0
  40. package/dist/options/lib/OptionConstant.js +3 -0
  41. package/package.json +1 -1
@@ -7,7 +7,7 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions, Nullable } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample, Nullable, Optional } from '@memlab/core';
11
11
  import { BaseOption } from '@memlab/core';
12
12
  export declare enum CommandCategory {
13
13
  COMMON = "COMMON",
@@ -24,7 +24,7 @@ declare abstract class Command {
24
24
  }
25
25
  export default class BaseCommand extends Command {
26
26
  getCommandName(): string;
27
- getExamples(): string[];
27
+ getExamples(): CommandOptionExample[];
28
28
  getCategory(): CommandCategory;
29
29
  getDescription(): string;
30
30
  getDocumenation(): string;
@@ -32,7 +32,7 @@ export default class BaseCommand extends Command {
32
32
  isInternalCommand(): boolean;
33
33
  getOptions(): BaseOption[];
34
34
  getExcludedOptions(): BaseOption[];
35
- getSubCommands(): BaseCommand[];
35
+ getSubCommands(): Optional<BaseCommand[]>;
36
36
  run(_options: CLIOptions): Promise<void>;
37
37
  }
38
38
  export {};
@@ -85,7 +85,7 @@ class BaseCommand extends Command {
85
85
  const className = this.constructor.name;
86
86
  throw new Error(`${className}.getCommandName is not implemented`);
87
87
  }
88
- // get a list of examples
88
+ // get a list of CLI option examples
89
89
  // examples will be displayed in helper text
90
90
  getExamples() {
91
91
  return [];
@@ -131,6 +131,10 @@ class BaseCommand extends Command {
131
131
  // for example command 'A' has two sub-commands 'B' and 'C'
132
132
  // CLI supports running in terminal: `memlab A B` or `memlab A C`
133
133
  // The parent command will be executed before its subcommands
134
+ //
135
+ // If this callback returns null or undefined, it means
136
+ // the command will handle the dispatcher won't try to match and process
137
+ // the subcommands (the command will handle sub-commands by itself).
134
138
  getSubCommands() {
135
139
  return [];
136
140
  }
@@ -107,6 +107,8 @@ class CommandDispatcher {
107
107
  const { configFromOptions } = runCmdOpt;
108
108
  // execute command
109
109
  yield command.run({ cliArgs: args, configFromOptions });
110
+ // recommand CLI command and flags
111
+ core_1.config.setRunInfo('command', process.argv.slice(2).join(' '));
110
112
  if (runCmdOpt.isPrerequisite !== true) {
111
113
  // execute subcommands
112
114
  const commandIndex = ((_a = runCmdOpt.commandIndex) !== null && _a !== void 0 ? _a : 0) + 1;
@@ -125,6 +127,10 @@ class CommandDispatcher {
125
127
  return;
126
128
  }
127
129
  const subCommands = command.getSubCommands();
130
+ // if the command will handle the sub-commands by itself
131
+ if (subCommands == null) {
132
+ return;
133
+ }
128
134
  for (const subCommand of subCommands) {
129
135
  if (subCommand.getCommandName() === args._[subCommandIndex]) {
130
136
  yield this.runCommand(subCommand, args, runCmdOpt);
@@ -7,12 +7,12 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { BaseOption, CLIOptions } from '@memlab/core';
10
+ import type { BaseOption, CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand, { CommandCategory } from '../BaseCommand';
12
12
  export default class MemLabRunCommand extends BaseCommand {
13
13
  getCommandName(): string;
14
14
  getDescription(): string;
15
- getExamples(): string[];
15
+ getExamples(): CommandOptionExample[];
16
16
  getPrerequisites(): BaseCommand[];
17
17
  getOptions(): BaseOption[];
18
18
  getExcludedOptions(): BaseOption[];
@@ -7,14 +7,14 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand from '../BaseCommand';
12
12
  import { BaseOption } from '@memlab/core';
13
13
  export default class RunMeasureCommand extends BaseCommand {
14
14
  getCommandName(): string;
15
15
  getDescription(): string;
16
16
  getPrerequisites(): BaseCommand[];
17
- getExamples(): string[];
17
+ getExamples(): CommandOptionExample[];
18
18
  getOptions(): BaseOption[];
19
19
  run(options: CLIOptions): Promise<void>;
20
20
  }
@@ -45,6 +45,7 @@ const HeadfulBrowserOption_1 = __importDefault(require("../options/e2e/HeadfulBr
45
45
  const DisableWebSecurityOption_1 = __importDefault(require("../options/e2e/DisableWebSecurityOption"));
46
46
  const EnableJSRewriteOption_1 = __importDefault(require("../options/e2e/EnableJSRewriteOption"));
47
47
  const EnableJSInterceptOption_1 = __importDefault(require("../options/e2e/EnableJSInterceptOption"));
48
+ const SetChromiumBinaryOption_1 = __importDefault(require("../options/e2e/SetChromiumBinaryOption"));
48
49
  class RunMeasureCommand extends BaseCommand_1.default {
49
50
  getCommandName() {
50
51
  return 'measure';
@@ -77,6 +78,7 @@ class RunMeasureCommand extends BaseCommand_1.default {
77
78
  new RunningModeOption_1.default(),
78
79
  new RemoteBrowserDebugOption_1.default(),
79
80
  new ScenarioFileOption_1.default(),
81
+ new SetChromiumBinaryOption_1.default(),
80
82
  new SetDeviceOption_1.default(),
81
83
  new SetUserAgentOption_1.default(),
82
84
  new DisableXvfbOption_1.default(),
@@ -7,14 +7,14 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import { BaseOption } from '@memlab/core';
12
12
  import BaseCommand from '../BaseCommand';
13
13
  export default class FBWarmupAppCommand extends BaseCommand {
14
14
  getCommandName(): string;
15
15
  getDescription(): string;
16
16
  getPrerequisites(): BaseCommand[];
17
- getExamples(): string[];
17
+ getExamples(): CommandOptionExample[];
18
18
  getOptions(): BaseOption[];
19
19
  run(_options: CLIOptions): Promise<void>;
20
20
  }
@@ -38,6 +38,7 @@ const HeadfulBrowserOption_1 = __importDefault(require("../options/e2e/HeadfulBr
38
38
  const DisableWebSecurityOption_1 = __importDefault(require("../options/e2e/DisableWebSecurityOption"));
39
39
  const EnableJSRewriteOption_1 = __importDefault(require("../options/e2e/EnableJSRewriteOption"));
40
40
  const EnableJSInterceptOption_1 = __importDefault(require("../options/e2e/EnableJSInterceptOption"));
41
+ const SetChromiumBinaryOption_1 = __importDefault(require("../options/e2e/SetChromiumBinaryOption"));
41
42
  class FBWarmupAppCommand extends BaseCommand_1.default {
42
43
  getCommandName() {
43
44
  return 'warmup';
@@ -62,6 +63,7 @@ class FBWarmupAppCommand extends BaseCommand_1.default {
62
63
  new RunningModeOption_1.default(),
63
64
  new RemoteBrowserDebugOption_1.default(),
64
65
  new ScenarioFileOption_1.default(),
66
+ new SetChromiumBinaryOption_1.default(),
65
67
  new SetDeviceOption_1.default(),
66
68
  new SetUserAgentOption_1.default(),
67
69
  new DisableXvfbOption_1.default(),
@@ -8,7 +8,7 @@
8
8
  * @oncall web_perf_infra
9
9
  */
10
10
  import type { ParsedArgs } from 'minimist';
11
- import type { BaseOption, CLIOptions } from '@memlab/core';
11
+ import type { BaseOption, CLIOptions, CommandOptionExample } from '@memlab/core';
12
12
  import BaseCommand, { CommandCategory } from '../../BaseCommand';
13
13
  export declare type CheckLeakCommandOptions = {
14
14
  isMLClustering?: boolean;
@@ -20,6 +20,7 @@ export default class CheckLeakCommand extends BaseCommand {
20
20
  protected restoreDefaultMLClusteringSetting(cliArgs: ParsedArgs): void;
21
21
  constructor(options?: CheckLeakCommandOptions);
22
22
  getCommandName(): string;
23
+ getExamples(): CommandOptionExample[];
23
24
  getDescription(): string;
24
25
  getDocumenation(): string;
25
26
  getCategory(): CommandCategory;
@@ -54,6 +54,7 @@ const MLClusteringLinkageMaxDistanceOption_1 = __importDefault(require("../../op
54
54
  const MLClusteringMaxDFOption_1 = __importDefault(require("../../options/MLClusteringMaxDFOption"));
55
55
  const CleanupSnapshotOption_1 = __importDefault(require("../../options/heap/CleanupSnapshotOption"));
56
56
  const SetWorkingDirectoryOption_1 = __importDefault(require("../../options/SetWorkingDirectoryOption"));
57
+ const OptionConstant_1 = __importDefault(require("../../options/lib/OptionConstant"));
57
58
  class CheckLeakCommand extends BaseCommand_1.default {
58
59
  constructor(options = {}) {
59
60
  super();
@@ -75,16 +76,54 @@ class CheckLeakCommand extends BaseCommand_1.default {
75
76
  getCommandName() {
76
77
  return 'find-leaks';
77
78
  }
79
+ getExamples() {
80
+ const optionNames = OptionConstant_1.default.optionNames;
81
+ const workDirOption = `--${optionNames.WORK_DIR}`;
82
+ const snapshotDirOption = `--${optionNames.SNAPSHOT_DIR}`;
83
+ const baselineOption = `--${optionNames.BASELINE}`;
84
+ const targetOption = `--${optionNames.TARGET}`;
85
+ const finalOption = `--${optionNames.FINAL}`;
86
+ return [
87
+ {
88
+ description: 'check memory leaks in the default working directory generated by\n' +
89
+ `memlab run (without setting the ${workDirOption} option)`,
90
+ cliOptionExample: '', // default empty command options
91
+ },
92
+ {
93
+ description: 'specify the baseline, target, and final heap snapshot file path separately',
94
+ cliOptionExample: `${baselineOption} /tmp/baseline.heapsnapshot ${targetOption} /tmp/target.heapsnapshot ${finalOption} /tmp/final.heapsnapshot`,
95
+ },
96
+ {
97
+ description: 'specifies the directory that holds all three heap snapshot files',
98
+ cliOptionExample: `${snapshotDirOption} /dir/containing/heapsnapshot/files/`,
99
+ },
100
+ {
101
+ description: 'specifies the output working directory of the `memlab run` or the `memlab snapshot` command',
102
+ cliOptionExample: `${workDirOption} /memlab/working/dir/generated/by/memlab/`,
103
+ },
104
+ ];
105
+ }
78
106
  getDescription() {
79
107
  return 'find memory leaks in heap snapshots';
80
108
  }
81
109
  getDocumenation() {
82
- return `There are three ways to specify inputs for the \`memlab find-leaks\` command:
83
- 1. \`--baseline\`, \`--target\`, \`--final\` specifies each snapshot input individually;
84
- 2. \`--snapshot-dir\` specifies the directory that holds all three heap snapshot files (MemLab will assign baseline, target, and final based on alphabetic order of the file);
85
- 3. \`--work-dir\` specifies the output working directory of the \`memlab run\` or the \`memlab snapshot\` command;
110
+ const optionNames = OptionConstant_1.default.optionNames;
111
+ const workDirOption = `--${optionNames.WORK_DIR}`;
112
+ const snapshotDirOption = `--${optionNames.SNAPSHOT_DIR}`;
113
+ const baselineOption = `--${optionNames.BASELINE}`;
114
+ const targetOption = `--${optionNames.TARGET}`;
115
+ const finalOption = `--${optionNames.FINAL}`;
116
+ return `There are three ways to specify inputs for the \`memlab ${this.getCommandName()}\` command:
117
+ 1. \`${baselineOption}\`, \`${targetOption}\`, \`${finalOption}\` specifies each heap snapshot input individually;
118
+ 2. \`${snapshotDirOption}\` specifies the directory that holds all three heap snapshot files (MemLab will assign baseline, target, and final based on alphabetic order of the file);
119
+ 3. \`${workDirOption}\` specifies the output working directory of the \`memlab run\` or the \`memlab snapshot\` command;
120
+
121
+ Please only use one of the three ways to specify the input.
86
122
 
87
- Please only use one of the three ways to specify the input.`;
123
+ You can also manually take heap snapshots in Chrome Devtools, save them to disk.
124
+ Then process them using this command with the CLI flags (either option 1
125
+ or option 2 mentioned above).
126
+ `;
88
127
  }
89
128
  getCategory() {
90
129
  return BaseCommand_1.CommandCategory.COMMON;
@@ -7,14 +7,26 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { BaseOption, CLIOptions } from '@memlab/core';
10
+ import type { ParsedArgs } from 'minimist';
11
+ import { BaseOption, CLIOptions } from '@memlab/core';
12
+ import type { CheckLeakCommandOptions } from './CheckLeakCommand';
11
13
  import BaseCommand, { CommandCategory } from '../../BaseCommand';
14
+ export declare type WorkDirSettings = {
15
+ controlWorkDirs: Array<string>;
16
+ treatmentWorkDir: string;
17
+ };
12
18
  export default class CheckLeakCommand extends BaseCommand {
19
+ private isMLClustering;
20
+ private isMLClusteringSettingCache;
21
+ protected useDefaultMLClusteringSetting(cliArgs: ParsedArgs): void;
22
+ protected restoreDefaultMLClusteringSetting(cliArgs: ParsedArgs): void;
23
+ constructor(options?: CheckLeakCommandOptions);
13
24
  getCommandName(): string;
14
25
  getDescription(): string;
15
26
  getCategory(): CommandCategory;
16
27
  getPrerequisites(): BaseCommand[];
17
28
  getOptions(): BaseOption[];
29
+ protected getWorkDirs(options: CLIOptions): WorkDirSettings;
18
30
  run(options: CLIOptions): Promise<void>;
19
31
  }
20
32
  //# sourceMappingURL=DiffLeakCommand.d.ts.map
@@ -50,7 +50,26 @@ const MLClusteringLinkageMaxDistanceOption_1 = __importDefault(require("../../op
50
50
  const MLClusteringMaxDFOption_1 = __importDefault(require("../../options/MLClusteringMaxDFOption"));
51
51
  const SetControlWorkDirOption_1 = __importDefault(require("../../options/experiment/SetControlWorkDirOption"));
52
52
  const SetTreatmentWorkDirOption_1 = __importDefault(require("../../options/experiment/SetTreatmentWorkDirOption"));
53
+ const SetMaxClusterSampleSizeOption_1 = __importDefault(require("../../options/SetMaxClusterSampleSizeOption"));
54
+ const SetTraceContainsFilterOption_1 = __importDefault(require("../../options/heap/SetTraceContainsFilterOption"));
53
55
  class CheckLeakCommand extends BaseCommand_1.default {
56
+ constructor(options = {}) {
57
+ super();
58
+ this.isMLClustering = false;
59
+ this.isMLClusteringSettingCache = false;
60
+ this.isMLClustering = !!(options === null || options === void 0 ? void 0 : options.isMLClustering);
61
+ }
62
+ useDefaultMLClusteringSetting(cliArgs) {
63
+ if (!MLClusteringOption_1.default.hasOptionSet(cliArgs)) {
64
+ core_1.config.isMLClustering = this.isMLClustering;
65
+ this.isMLClusteringSettingCache = core_1.config.isMLClustering;
66
+ }
67
+ }
68
+ restoreDefaultMLClusteringSetting(cliArgs) {
69
+ if (!MLClusteringOption_1.default.hasOptionSet(cliArgs)) {
70
+ core_1.config.isMLClustering = this.isMLClusteringSettingCache;
71
+ }
72
+ }
54
73
  getCommandName() {
55
74
  return 'diff-leaks';
56
75
  }
@@ -65,8 +84,8 @@ class CheckLeakCommand extends BaseCommand_1.default {
65
84
  }
66
85
  getOptions() {
67
86
  return [
68
- new SetControlWorkDirOption_1.default().required(),
69
- new SetTreatmentWorkDirOption_1.default().required(),
87
+ new SetControlWorkDirOption_1.default(),
88
+ new SetTreatmentWorkDirOption_1.default(),
70
89
  new JSEngineOption_1.default(),
71
90
  new LeakFilterFileOption_1.default(),
72
91
  new OversizeThresholdOption_1.default(),
@@ -76,28 +95,39 @@ class CheckLeakCommand extends BaseCommand_1.default {
76
95
  new MLClusteringOption_1.default(),
77
96
  new MLClusteringLinkageMaxDistanceOption_1.default(),
78
97
  new MLClusteringMaxDFOption_1.default(),
98
+ new SetMaxClusterSampleSizeOption_1.default(),
99
+ new SetTraceContainsFilterOption_1.default(),
79
100
  ];
80
101
  }
81
- run(options) {
102
+ getWorkDirs(options) {
82
103
  var _a, _b;
104
+ // double check parameters
105
+ if (!((_a = options.configFromOptions) === null || _a === void 0 ? void 0 : _a.controlWorkDirs) ||
106
+ !((_b = options.configFromOptions) === null || _b === void 0 ? void 0 : _b.treatmentWorkDir)) {
107
+ core_1.info.error('Please specify control and test working directory');
108
+ throw core_1.utils.haltOrThrow('No control or test working directory specified');
109
+ }
110
+ // get parameters
111
+ const controlWorkDirs = options.configFromOptions['controlWorkDirs'];
112
+ const treatmentWorkDir = options.configFromOptions['treatmentWorkDir'];
113
+ return {
114
+ controlWorkDirs,
115
+ treatmentWorkDir,
116
+ };
117
+ }
118
+ run(options) {
83
119
  return __awaiter(this, void 0, void 0, function* () {
84
120
  core_1.config.chaseWeakMapEdge = false;
85
- // double check parameters
86
- if (!((_a = options.configFromOptions) === null || _a === void 0 ? void 0 : _a.controlWorkDirs) ||
87
- !((_b = options.configFromOptions) === null || _b === void 0 ? void 0 : _b.treatmentWorkDir)) {
88
- core_1.info.error('Please specify control and test working directory');
89
- throw core_1.utils.haltOrThrow('No control or test working directory specified');
90
- }
91
- // get parameters
92
- const controlWorkDirs = options.configFromOptions['controlWorkDirs'];
93
- const treatmentWorkDir = options.configFromOptions['treatmentWorkDir'];
121
+ const { controlWorkDirs, treatmentWorkDir } = this.getWorkDirs(options);
94
122
  const { runMetaInfoManager } = core_1.runInfoUtils;
95
123
  runMetaInfoManager.setConfigFromRunMeta({
96
124
  workDir: treatmentWorkDir,
97
125
  silentFail: true,
98
126
  });
99
127
  // diff memory leaks
128
+ this.useDefaultMLClusteringSetting(options.cliArgs);
100
129
  yield core_1.analysis.diffLeakByWorkDir({ controlWorkDirs, treatmentWorkDir });
130
+ this.restoreDefaultMLClusteringSetting(options.cliArgs);
101
131
  });
102
132
  }
103
133
  }
@@ -7,14 +7,14 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand, { CommandCategory } from '../../BaseCommand';
12
12
  import { BaseOption } from '@memlab/core';
13
13
  export default class GetRetainerTraceCommand extends BaseCommand {
14
14
  getCommandName(): string;
15
15
  getDescription(): string;
16
16
  getCategory(): CommandCategory;
17
- getExamples(): string[];
17
+ getExamples(): CommandOptionExample[];
18
18
  getOptions(): BaseOption[];
19
19
  run(options: CLIOptions): Promise<void>;
20
20
  }
@@ -7,7 +7,7 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand, { CommandCategory } from '../../BaseCommand';
12
12
  export default class RunHeapAnalysisCommand extends BaseCommand {
13
13
  getCommandName(): string;
@@ -15,7 +15,7 @@ export default class RunHeapAnalysisCommand extends BaseCommand {
15
15
  getCategory(): CommandCategory;
16
16
  getPrerequisites(): BaseCommand[];
17
17
  getSubCommands(): BaseCommand[];
18
- getExamples(): string[];
18
+ getExamples(): CommandOptionExample[];
19
19
  run(options: CLIOptions): Promise<void>;
20
20
  }
21
21
  //# sourceMappingURL=HeapAnalysisCommand.d.ts.map
@@ -7,14 +7,14 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import { CLIOptions } from '@memlab/core';
10
+ import { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand, { CommandCategory } from '../../../BaseCommand';
12
12
  import { BaseOption } from '@memlab/core';
13
13
  export default class InteractiveHeapCommand extends BaseCommand {
14
14
  getCommandName(): string;
15
15
  getDescription(): string;
16
16
  getCategory(): CommandCategory;
17
- getExamples(): string[];
17
+ getExamples(): CommandOptionExample[];
18
18
  getOptions(): BaseOption[];
19
19
  private exitAttempt;
20
20
  private printPromptInfo;
@@ -7,13 +7,13 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { BaseOption, CLIOptions } from '@memlab/core';
10
+ import type { BaseOption, CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand, { CommandCategory } from '../../../BaseCommand';
12
12
  export default class InteractiveHeapViewCommand extends BaseCommand {
13
13
  getCommandName(): string;
14
14
  getDescription(): string;
15
15
  getCategory(): CommandCategory;
16
- getExamples(): string[];
16
+ getExamples(): CommandOptionExample[];
17
17
  getOptions(): BaseOption[];
18
18
  private getHeap;
19
19
  private getNodesToFocus;
@@ -17,6 +17,8 @@ export declare class ComponentDataItem {
17
17
  type?: string;
18
18
  details?: Map<string, string>;
19
19
  static getTextForDisplay(data: ComponentDataItem): string;
20
+ private static getHeapObjectTextContent;
21
+ private static getHeapEdgeTextContent;
20
22
  private static getTextContent;
21
23
  }
22
24
  export declare class ComponentData {
@@ -66,6 +66,28 @@ class ComponentDataItem {
66
66
  }
67
67
  return chalk_1.default.grey(content);
68
68
  }
69
+ static getHeapObjectTextContent(node) {
70
+ const objectType = chalk_1.default.grey(`(${node.type})`);
71
+ const objectId = chalk_1.default.grey(` @${node.id}`);
72
+ const size = core_1.utils.getReadableBytes(node.retainedSize);
73
+ const sizeInfo = chalk_1.default.grey(' [') + chalk_1.default.bold(chalk_1.default.blue(size)) + chalk_1.default.grey(']');
74
+ const objectTitle = node.isString ? '<string>' : node.name;
75
+ return (chalk_1.default.green('[') +
76
+ (isUsefulObjectForDebugging(node)
77
+ ? chalk_1.default.green(objectTitle)
78
+ : chalk_1.default.bold(chalk_1.default.grey(objectTitle))) +
79
+ chalk_1.default.green(']') +
80
+ objectType +
81
+ objectId +
82
+ sizeInfo);
83
+ }
84
+ static getHeapEdgeTextContent(edge) {
85
+ const arrowPrefix = chalk_1.default.grey('--');
86
+ const arrowSuffix = chalk_1.default.grey('---') + '>';
87
+ const edgeType = chalk_1.default.grey(`(${edge.type})`);
88
+ const edgeName = edge.name_or_index;
89
+ return `${arrowPrefix}${edgeName}${edgeType}${arrowSuffix} `;
90
+ }
69
91
  static getTextContent(data) {
70
92
  let ret = '';
71
93
  if (data.tag) {
@@ -74,32 +96,14 @@ class ComponentDataItem {
74
96
  if (data.stringContent) {
75
97
  ret += data.stringContent;
76
98
  }
77
- const arrowPrefix = chalk_1.default.grey('--');
78
- const arrowSuffix = chalk_1.default.grey('---') + '>';
79
99
  if (data.referrerEdge) {
80
- const edgeType = chalk_1.default.grey(`(${data.referrerEdge.type})`);
81
- const edgeName = data.referrerEdge.name_or_index;
82
- ret += `${arrowPrefix}${edgeName}${edgeType}${arrowSuffix} `;
100
+ ret += this.getHeapEdgeTextContent(data.referrerEdge);
83
101
  }
84
102
  if (data.heapObject) {
85
- const objectType = chalk_1.default.grey(`(${data.heapObject.type})`);
86
- const objectId = chalk_1.default.grey(` @${data.heapObject.id}`);
87
- const size = core_1.utils.getReadableBytes(data.heapObject.retainedSize);
88
- const sizeInfo = chalk_1.default.grey(' [') + chalk_1.default.bold(chalk_1.default.blue(size)) + chalk_1.default.grey(']');
89
- ret +=
90
- chalk_1.default.green('[') +
91
- (isUsefulObjectForDebugging(data.heapObject)
92
- ? chalk_1.default.green(data.heapObject.name)
93
- : chalk_1.default.bold(chalk_1.default.grey(data.heapObject.name))) +
94
- chalk_1.default.green(']') +
95
- objectType +
96
- objectId +
97
- sizeInfo;
103
+ ret += this.getHeapObjectTextContent(data.heapObject);
98
104
  }
99
105
  if (data.referenceEdge) {
100
- const edgeType = chalk_1.default.grey(`(${data.referenceEdge.type})`);
101
- const edgeName = data.referenceEdge.name_or_index;
102
- ret += ` ${arrowPrefix}${edgeName}${edgeType}${arrowSuffix} `;
106
+ ret += this.getHeapEdgeTextContent(data.referenceEdge);
103
107
  }
104
108
  return ret === '' ? chalk_1.default.grey('<undefinied>') : ret;
105
109
  }
@@ -203,7 +203,7 @@ class ListComponent {
203
203
  this.element.pushItem(content[i]);
204
204
  ++this.displayedItems;
205
205
  }
206
- this.content = content;
206
+ this.content = content.map(v => v.replace(/\n/g, '\\n'));
207
207
  this.horizonScrollPositionMap.clear();
208
208
  this.insertDisplayMoreEntry();
209
209
  this.updateContent(oldContent, this.content);
@@ -46,6 +46,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
46
46
  Object.defineProperty(exports, "__esModule", { value: true });
47
47
  const path_1 = __importDefault(require("path"));
48
48
  const fs_extra_1 = __importDefault(require("fs-extra"));
49
+ const DocUtils_1 = __importDefault(require("./lib/DocUtils"));
49
50
  const BaseCommand_1 = __importStar(require("../../BaseCommand"));
50
51
  const core_1 = require("@memlab/core");
51
52
  const UniversalOptions_1 = __importDefault(require("../../options/lib/UniversalOptions"));
@@ -86,6 +87,10 @@ class GenerateCLIDocCommand extends BaseCommand_1.default {
86
87
  }
87
88
  writeCommandCategories(docFile) {
88
89
  this.writeTextWithNewLine(docFile, '# Command Line Interface');
90
+ this.writeTextWithNewLine(docFile, `Install the memlab command line tool with npm:
91
+ \`\`\`bash
92
+ npm install -g memlab
93
+ \`\`\``);
89
94
  for (const category in BaseCommand_1.CommandCategory) {
90
95
  const commandsToPrintFirst = [];
91
96
  this.writeCategory(docFile, category, commandsToPrintFirst);
@@ -131,6 +136,7 @@ class GenerateCLIDocCommand extends BaseCommand_1.default {
131
136
  this.writeTextWithNewLine(docFile, `\n## ${categoryName} Commands\n`);
132
137
  }
133
138
  writeCommand(docFile, command, indent = '') {
139
+ var _a, _b;
134
140
  const name = command.getFullCommand();
135
141
  const desc = core_1.utils.upperCaseFirstCharacter(command.getDescription().trim());
136
142
  const cmdDoc = command.getDocumenation().trim();
@@ -144,17 +150,14 @@ class GenerateCLIDocCommand extends BaseCommand_1.default {
144
150
  }
145
151
  // get example
146
152
  const examples = command.getExamples();
147
- let example = '';
148
- if (examples.length > 0) {
149
- example = examples[0].trim();
150
- }
153
+ const example = (_a = examples[0]) !== null && _a !== void 0 ? _a : '';
151
154
  // write command synopsis
152
- const cmd = `memlab ${name} ${example}`;
155
+ const cmd = DocUtils_1.default.generateExampleCommand(name, example);
153
156
  this.writeCodeBlock(docFile, cmd, 'bash');
154
157
  // write command examples if there is any
155
158
  const exampleBlock = examples
156
159
  .slice(1)
157
- .map(example => `memlab ${name} ${example.trim()}`)
160
+ .map(example => DocUtils_1.default.generateExampleCommand(name, example))
158
161
  .join('\n');
159
162
  if (exampleBlock.length > 0) {
160
163
  this.writeTextWithNewLine(docFile, '\n#### examples\n');
@@ -162,7 +165,7 @@ class GenerateCLIDocCommand extends BaseCommand_1.default {
162
165
  }
163
166
  // write options
164
167
  this.writeCommandOptions(docFile, command);
165
- const subCommands = command.getSubCommands();
168
+ const subCommands = (_b = command.getSubCommands()) !== null && _b !== void 0 ? _b : [];
166
169
  for (const subCommand of subCommands) {
167
170
  this.writeCommand(docFile, subCommand, indent + '#');
168
171
  }
@@ -7,20 +7,23 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { BaseOption, CLIOptions } from '@memlab/core';
10
+ import type { BaseOption, CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand from '../../BaseCommand';
12
- declare type HelperOption = CLIOptions & {
12
+ declare type PrintCommandOptions = {
13
+ printOptions?: boolean;
14
+ printDoc?: boolean;
15
+ };
16
+ declare type HelperOption = CLIOptions & PrintCommandOptions & {
13
17
  modules: Map<string, BaseCommand>;
14
18
  command: BaseCommand | null;
15
19
  indent?: string;
16
- printOptions?: boolean;
17
20
  };
18
21
  export default class HelperCommand extends BaseCommand {
19
22
  private printedCommand;
20
23
  private universalOptions;
21
24
  getCommandName(): string;
22
25
  getDescription(): string;
23
- getExamples(): string[];
26
+ getExamples(): CommandOptionExample[];
24
27
  setUniversalOptions(options: BaseOption[]): void;
25
28
  private printHeader;
26
29
  private printCommandCategories;
@@ -49,6 +49,7 @@ const chalk_1 = __importDefault(require("chalk"));
49
49
  const string_width_1 = __importDefault(require("string-width"));
50
50
  const core_1 = require("@memlab/core");
51
51
  const heap_analysis_1 = require("@memlab/heap-analysis");
52
+ const DocUtils_1 = __importDefault(require("./lib/DocUtils"));
52
53
  const CommandOrder_1 = __importDefault(require("./lib/CommandOrder"));
53
54
  const BaseCommand_1 = __importStar(require("../../BaseCommand"));
54
55
  const UniversalOptions_1 = __importDefault(require("../../options/lib/UniversalOptions"));
@@ -188,21 +189,22 @@ class HelperCommand extends BaseCommand_1.default {
188
189
  });
189
190
  return `${headerString}${descString.substring(headerStringWidth)}`;
190
191
  }
191
- printCommand(command, extraIndent = '', printOptions = false) {
192
+ printCommand(command, extraIndent = '', options = {}) {
193
+ var _a;
192
194
  const indent = ' ' + extraIndent;
193
195
  const name = command.getFullCommand();
194
196
  const desc = core_1.utils.upperCaseFirstCharacter(command.getDescription().trim());
195
197
  const cmdDoc = command.getDocumenation().trim();
196
198
  // get example
197
199
  const examples = command.getExamples();
198
- let example = '';
199
- if (examples.length > 0) {
200
- example = ' ' + examples[0].trim();
201
- }
202
- const cmd = chalk_1.default.green(`memlab ${name}${example}`);
200
+ const example = (_a = examples[0]) !== null && _a !== void 0 ? _a : '';
201
+ // write command synopsis
202
+ const cmd = DocUtils_1.default.generateExampleCommand(name, example, {
203
+ descriptionAsBashComment: false,
204
+ });
203
205
  let msg = `${indent}${cmd}`;
204
206
  msg += `\n${indent}${desc}`;
205
- if (cmdDoc.length > 0) {
207
+ if (options.printOptions && cmdDoc.length > 0) {
206
208
  const cmdDocBlock = (0, CLIUtils_1.alignTextInBlock)(cmdDoc, {
207
209
  leftIndent: indent.length + 2,
208
210
  });
@@ -210,7 +212,7 @@ class HelperCommand extends BaseCommand_1.default {
210
212
  }
211
213
  core_1.info.topLevel(msg);
212
214
  // print options info
213
- if (printOptions) {
215
+ if (options.printOptions) {
214
216
  // print full options description
215
217
  this.printOptions(command, indent);
216
218
  }
@@ -224,11 +226,12 @@ class HelperCommand extends BaseCommand_1.default {
224
226
  core_1.info.topLevel('');
225
227
  }
226
228
  printHelperTextForCommand(command, options) {
229
+ var _a;
227
230
  return __awaiter(this, void 0, void 0, function* () {
228
231
  // print helper text for a specific command
229
- this.printCommand(command, options.indent, options.printOptions);
232
+ this.printCommand(command, options.indent, options);
230
233
  // print helper text for its subcommands
231
- const subcommands = command.getSubCommands();
234
+ const subcommands = (_a = command.getSubCommands()) !== null && _a !== void 0 ? _a : [];
232
235
  const subOptions = Object.assign({}, options);
233
236
  subOptions.indent = (subOptions.indent || '') + ' ';
234
237
  for (const subcommand of subcommands) {
@@ -238,6 +241,7 @@ class HelperCommand extends BaseCommand_1.default {
238
241
  });
239
242
  }
240
243
  printFullHelperTextForCommand(args, modules) {
244
+ var _a, _b;
241
245
  return __awaiter(this, void 0, void 0, function* () {
242
246
  // get the command to print
243
247
  let map = modules;
@@ -252,7 +256,7 @@ class HelperCommand extends BaseCommand_1.default {
252
256
  if (!command) {
253
257
  break;
254
258
  }
255
- const subCommands = command.getSubCommands();
259
+ const subCommands = (_a = command.getSubCommands()) !== null && _a !== void 0 ? _a : [];
256
260
  map = new Map(subCommands.map((cmd) => [cmd.getCommandName(), cmd]));
257
261
  }
258
262
  if (!command) {
@@ -260,9 +264,9 @@ class HelperCommand extends BaseCommand_1.default {
260
264
  }
261
265
  // print the helper text of the command
262
266
  core_1.info.topLevel('');
263
- this.printCommand(command, '', true);
267
+ this.printCommand(command, '', { printOptions: true, printDoc: true });
264
268
  // print the helper text of the subcommands
265
- const subCommands = command.getSubCommands();
269
+ const subCommands = (_b = command.getSubCommands()) !== null && _b !== void 0 ? _b : [];
266
270
  if (subCommands.length > 0) {
267
271
  core_1.info.topLevel(chalk_1.default.bold(' SUB-COMMANDS\n'));
268
272
  for (const subCommand of subCommands) {
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall web_perf_infra
9
+ */
10
+ import type { CommandOptionExample } from '@memlab/core';
11
+ declare type GenerateExampleCommandOption = {
12
+ descriptionAsBashComment?: boolean;
13
+ };
14
+ declare function generateExampleCommand(command: string, cliExample: CommandOptionExample, options?: GenerateExampleCommandOption): string;
15
+ declare const _default: {
16
+ generateExampleCommand: typeof generateExampleCommand;
17
+ };
18
+ export default _default;
19
+ //# sourceMappingURL=DocUtils.d.ts.map
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @format
9
+ * @oncall web_perf_infra
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ function generateExampleCommand(command, cliExample, options = {}) {
13
+ if (typeof cliExample === 'string') {
14
+ return exampleFromCliOptionString(command, cliExample);
15
+ }
16
+ let commandExample = '';
17
+ if (cliExample.description != null &&
18
+ // if it's not null, undefined, or true
19
+ options.descriptionAsBashComment !== false) {
20
+ const desc = cliExample.description.trim();
21
+ if (desc.length > 0) {
22
+ // inject the description as a bash command in the bash example
23
+ const bashText = cliExample.description
24
+ .trim()
25
+ .split('\n')
26
+ .map(line => `# ${line.trim()}`)
27
+ .join('\n');
28
+ commandExample += bashText + '\n';
29
+ }
30
+ }
31
+ commandExample += exampleFromCliOptionString(command, cliExample.cliOptionExample);
32
+ return commandExample;
33
+ }
34
+ function exampleFromCliOptionString(command, cliExample) {
35
+ return `memlab ${command} ${cliExample.trim()}`;
36
+ }
37
+ exports.default = {
38
+ generateExampleCommand,
39
+ };
@@ -7,14 +7,14 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand from '../../BaseCommand';
12
12
  import { BaseOption } from '@memlab/core';
13
13
  export default class TakeSnapshotCommand extends BaseCommand {
14
14
  getCommandName(): string;
15
15
  getDescription(): string;
16
16
  getPrerequisites(): BaseCommand[];
17
- getExamples(): string[];
17
+ getExamples(): CommandOptionExample[];
18
18
  getOptions(): BaseOption[];
19
19
  run(_options: CLIOptions): Promise<void>;
20
20
  }
@@ -45,6 +45,7 @@ const DisableWebSecurityOption_1 = __importDefault(require("../../options/e2e/Di
45
45
  const EnableJSRewriteOption_1 = __importDefault(require("../../options/e2e/EnableJSRewriteOption"));
46
46
  const EnableJSInterceptOption_1 = __importDefault(require("../../options/e2e/EnableJSInterceptOption"));
47
47
  const TargetWorkerOption_1 = __importDefault(require("../../options/e2e/TargetWorkerOption"));
48
+ const SetChromiumBinaryOption_1 = __importDefault(require("../../options/e2e/SetChromiumBinaryOption"));
48
49
  class TakeSnapshotCommand extends BaseCommand_1.default {
49
50
  getCommandName() {
50
51
  return 'snapshot';
@@ -80,6 +81,7 @@ class TakeSnapshotCommand extends BaseCommand_1.default {
80
81
  new RunningModeOption_1.default(),
81
82
  new RemoteBrowserDebugOption_1.default(),
82
83
  new ScenarioFileOption_1.default(),
84
+ new SetChromiumBinaryOption_1.default(),
83
85
  new SetDeviceOption_1.default(),
84
86
  new SetUserAgentOption_1.default(),
85
87
  new DisableXvfbOption_1.default(),
@@ -7,11 +7,13 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { CLIOptions } from '@memlab/core';
10
+ import type { CLIOptions, CommandOptionExample } from '@memlab/core';
11
11
  import BaseCommand from '../../BaseCommand';
12
12
  export default class WarmupAndSnapshotCommand extends BaseCommand {
13
13
  getCommandName(): string;
14
14
  getDescription(): string;
15
+ getDocumenation(): string;
16
+ getExamples(): CommandOptionExample[];
15
17
  getPrerequisites(): BaseCommand[];
16
18
  run(_options: CLIOptions): Promise<void>;
17
19
  }
@@ -22,6 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
24
  const BaseCommand_1 = __importDefault(require("../../BaseCommand"));
25
+ const SetWorkingDirectoryOption_1 = __importDefault(require("../../options/SetWorkingDirectoryOption"));
25
26
  const InitDirectoryCommand_1 = __importDefault(require("../InitDirectoryCommand"));
26
27
  const WarmupAppCommand_1 = __importDefault(require("../WarmupAppCommand"));
27
28
  const TakeSnapshotCommand_1 = __importDefault(require("./TakeSnapshotCommand"));
@@ -32,6 +33,28 @@ class WarmupAndSnapshotCommand extends BaseCommand_1.default {
32
33
  getDescription() {
33
34
  return 'Warm up server and take heap snapshots';
34
35
  }
36
+ getDocumenation() {
37
+ const warmupCommand = new WarmupAppCommand_1.default();
38
+ const warmupCLI = `memlab ${warmupCommand.getCommandName()}`;
39
+ const takeSnapshotCommand = new TakeSnapshotCommand_1.default();
40
+ const snapshotCLI = `memlab ${takeSnapshotCommand.getCommandName()}`;
41
+ return ('This is equivalent to running ' +
42
+ `\`${warmupCLI}\` and \`${snapshotCLI}\`.`);
43
+ }
44
+ getExamples() {
45
+ return [
46
+ {
47
+ description: 'specify a test scenario file, memlab will ' +
48
+ 'warm up the server and take heap snapshots',
49
+ cliOptionExample: '--scenario <TEST_SCENARIO_FILE>',
50
+ },
51
+ '--scenario /tmp/test-scenario.js',
52
+ {
53
+ description: new SetWorkingDirectoryOption_1.default().getDescription(),
54
+ cliOptionExample: '--scenario /tmp/test-scenario.js --work-dir /tmp/test-1/',
55
+ },
56
+ ];
57
+ }
35
58
  getPrerequisites() {
36
59
  return [
37
60
  new InitDirectoryCommand_1.default(),
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall web_perf_infra
9
+ */
10
+ import type { ParsedArgs } from 'minimist';
11
+ import type { MemLabConfig } from '@memlab/core';
12
+ import { BaseOption } from '@memlab/core';
13
+ export default class SetMaxClusterSampleSizeOption extends BaseOption {
14
+ getOptionName(): string;
15
+ getDescription(): string;
16
+ getExampleValues(): string[];
17
+ parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=SetMaxClusterSampleSizeOption.d.ts.map
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @format
9
+ * @oncall web_perf_infra
10
+ */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ const core_1 = require("@memlab/core");
25
+ const OptionConstant_1 = __importDefault(require("./lib/OptionConstant"));
26
+ class SetMaxClusterSampleSizeOption extends core_1.BaseOption {
27
+ getOptionName() {
28
+ return OptionConstant_1.default.optionNames.MAX_CLUSTER_SAMPLE_SIZE;
29
+ }
30
+ getDescription() {
31
+ return ('specify the max number of leak traces as input to leak trace ' +
32
+ 'clustering algorithm. Big sample size will preserve more complete ' +
33
+ 'inforrmation, but may risk out-of-memory crash.');
34
+ }
35
+ getExampleValues() {
36
+ return ['5000', '10000'];
37
+ }
38
+ parse(config, args) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ if (args[this.getOptionName()]) {
41
+ const sampleSize = parseInt(args[this.getOptionName()], 10);
42
+ if (!isNaN(sampleSize)) {
43
+ config.maxSamplesForClustering = sampleSize;
44
+ }
45
+ }
46
+ });
47
+ }
48
+ }
49
+ exports.default = SetMaxClusterSampleSizeOption;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall web_perf_infra
9
+ */
10
+ import type { ParsedArgs } from 'minimist';
11
+ import { MemLabConfig } from '@memlab/core';
12
+ import { BaseOption } from '@memlab/core';
13
+ export default class SetChromiumBinaryOption extends BaseOption {
14
+ getOptionName(): string;
15
+ getDescription(): string;
16
+ parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=SetChromiumBinaryOption.d.ts.map
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const path_1 = __importDefault(require("path"));
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const core_1 = require("@memlab/core");
18
+ const OptionConstant_1 = __importDefault(require("../lib/OptionConstant"));
19
+ class SetChromiumBinaryOption extends core_1.BaseOption {
20
+ getOptionName() {
21
+ return OptionConstant_1.default.optionNames.CHROMIUM_BINARY;
22
+ }
23
+ getDescription() {
24
+ return 'set the chromium binary for E2E run';
25
+ }
26
+ parse(config, args) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ const name = this.getOptionName();
29
+ const arg = args[name];
30
+ if (arg) {
31
+ const binaryPath = path_1.default.resolve(process.cwd(), arg);
32
+ if (!fs_1.default.existsSync(binaryPath)) {
33
+ throw core_1.utils.haltOrThrow(`Chromium binary does not exist: ${binaryPath}`);
34
+ }
35
+ if (config.verbose) {
36
+ core_1.info.lowLevel(`Using ${binaryPath} as Chromium binary for E2E run`);
37
+ }
38
+ config.puppeteerConfig.executablePath = binaryPath;
39
+ }
40
+ });
41
+ }
42
+ }
43
+ exports.default = SetChromiumBinaryOption;
@@ -8,14 +8,14 @@
8
8
  * @oncall web_perf_infra
9
9
  */
10
10
  import type { ParsedArgs } from 'minimist';
11
- import type { MemLabConfig } from '@memlab/core';
11
+ import type { MemLabConfig, Nullable } from '@memlab/core';
12
12
  import { BaseOption } from '@memlab/core';
13
13
  export default class SetControlWorkDirOption extends BaseOption {
14
14
  getOptionName(): string;
15
15
  getDescription(): string;
16
- protected extractAndCheckWorkDirs(args: ParsedArgs): string[];
16
+ protected extractAndCheckWorkDirs(args: ParsedArgs): Nullable<string[]>;
17
17
  parse(config: MemLabConfig, args: ParsedArgs): Promise<{
18
- controlWorkDirs?: string[];
18
+ controlWorkDirs?: Nullable<string[]>;
19
19
  }>;
20
20
  }
21
21
  //# sourceMappingURL=SetControlWorkDirOption.d.ts.map
@@ -36,7 +36,7 @@ class SetControlWorkDirOption extends core_1.BaseOption {
36
36
  const name = this.getOptionName();
37
37
  const flagValue = args[name];
38
38
  if (!flagValue) {
39
- return dirs;
39
+ return null;
40
40
  }
41
41
  if (Array.isArray(flagValue)) {
42
42
  dirs = flagValue;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall web_perf_infra
9
+ */
10
+ import type { ParsedArgs } from 'minimist';
11
+ import type { MemLabConfig } from '@memlab/core';
12
+ import { BaseOption } from '@memlab/core';
13
+ export default class SetTraceContainsFilterOption extends BaseOption {
14
+ getOptionName(): string;
15
+ getDescription(): string;
16
+ parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=SetTraceContainsFilterOption.d.ts.map
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @format
9
+ * @oncall web_perf_infra
10
+ */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ const core_1 = require("@memlab/core");
25
+ const OptionConstant_1 = __importDefault(require("../lib/OptionConstant"));
26
+ class SetTraceContainsFilterOption extends core_1.BaseOption {
27
+ getOptionName() {
28
+ return OptionConstant_1.default.optionNames.TRACE_CONTAINS;
29
+ }
30
+ getDescription() {
31
+ return 'set the node name or edge name to filter leak traces that contain the name';
32
+ }
33
+ parse(config, args) {
34
+ return __awaiter(this, void 0, void 0, function* () {
35
+ const filterName = args[this.getOptionName()];
36
+ if (filterName != null) {
37
+ config.filterTraceByName = filterName;
38
+ }
39
+ });
40
+ }
41
+ }
42
+ exports.default = SetTraceContainsFilterOption;
@@ -8,11 +8,13 @@
8
8
  * @oncall web_perf_infra
9
9
  */
10
10
  import type { ParsedArgs } from 'minimist';
11
- import type { MemLabConfig } from '@memlab/core';
12
- import { BaseOption } from '@memlab/core';
11
+ import { MemLabConfig } from '@memlab/core';
12
+ import { BaseOption, TraceObjectMode } from '@memlab/core';
13
13
  export default class TraceAllObjectsOption extends BaseOption {
14
14
  getOptionName(): string;
15
15
  getDescription(): string;
16
+ getAvailableOptions(): Array<string>;
17
+ getMode(optionValue: string): TraceObjectMode;
16
18
  parse(config: MemLabConfig, args: ParsedArgs): Promise<void>;
17
19
  }
18
20
  //# sourceMappingURL=TraceAllObjectsOption.d.ts.map
@@ -22,26 +22,48 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
24
  const core_1 = require("@memlab/core");
25
+ const core_2 = require("@memlab/core");
25
26
  const OptionConstant_1 = __importDefault(require("../lib/OptionConstant"));
26
27
  const OversizeThresholdOption_1 = __importDefault(require("./OversizeThresholdOption"));
27
- class TraceAllObjectsOption extends core_1.BaseOption {
28
+ const optionMapping = new Map([
29
+ ['selected-js-objects', core_2.TraceObjectMode.SelectedJSObjects],
30
+ ['default', core_2.TraceObjectMode.Default],
31
+ ]);
32
+ class TraceAllObjectsOption extends core_2.BaseOption {
28
33
  getOptionName() {
29
34
  return OptionConstant_1.default.optionNames.TRACE_ALL_OBJECTS;
30
35
  }
31
36
  getDescription() {
32
- return 'dump retainer trace for all allocated objects (ignore the leak filter)';
37
+ return ('dump retainer trace for all allocated objects (ignore the leak filter), ' +
38
+ `available option modes: ${this.getAvailableOptions().join(', ')}`);
39
+ }
40
+ getAvailableOptions() {
41
+ return Array.from(optionMapping.keys()).map(mode => `--${this.getOptionName()}=${mode}`);
42
+ }
43
+ getMode(optionValue) {
44
+ // if the user specified an option value (--flag=value instead of --flag)
45
+ if (typeof optionValue === 'boolean') {
46
+ return optionMapping.get('default');
47
+ }
48
+ if (!optionMapping.has(optionValue)) {
49
+ throw core_1.utils.haltOrThrow(`Unknown option value ${optionValue}. ` +
50
+ `Available options: ${this.getAvailableOptions().join(', ')}`);
51
+ }
52
+ return optionMapping.get(optionValue);
33
53
  }
34
54
  parse(config, args) {
35
55
  return __awaiter(this, void 0, void 0, function* () {
36
- if (!args[this.getOptionName()]) {
56
+ const optionValue = args[this.getOptionName()];
57
+ if (optionValue == null) {
37
58
  return;
38
59
  }
39
60
  config.oversizeObjectAsLeak = true;
40
61
  const overSizeOptionName = new OversizeThresholdOption_1.default().getOptionName();
41
- // over size option will set the oversize threshold
62
+ // oversize option will set the oversize threshold
42
63
  if (!args[overSizeOptionName]) {
43
64
  config.oversizeThreshold = 0;
44
65
  }
66
+ config.traceAllObjectsMode = this.getMode(optionValue);
45
67
  });
46
68
  }
47
69
  }
@@ -14,6 +14,7 @@ declare const optionConstants: {
14
14
  CLEAN_UP_SNAPSHOT: string;
15
15
  CONTINUS_TEST: string;
16
16
  CONTROL_WORK_DIR: string;
17
+ CHROMIUM_BINARY: string;
17
18
  DEVICE: string;
18
19
  DISABLE_WEB_SECURITY: string;
19
20
  DISABLE_XVFB: string;
@@ -27,6 +28,7 @@ declare const optionConstants: {
27
28
  LEAK_FILTER: string;
28
29
  LOCAL_PUPPETEER: string;
29
30
  LOG_SCRIPT: string;
31
+ MAX_CLUSTER_SAMPLE_SIZE: string;
30
32
  ML_CLUSTERING: string;
31
33
  ML_CLUSTERING_MAX_DF: string;
32
34
  ML_LINKAGE_MAX_DIST: string;
@@ -49,6 +51,7 @@ declare const optionConstants: {
49
51
  SNAPSHOT_DIR: string;
50
52
  TARGET: string;
51
53
  TRACE_ALL_OBJECTS: string;
54
+ TRACE_CONTAINS: string;
52
55
  TRACE_OBJECT_SIZE_ABOVE: string;
53
56
  TREATMENT_WORK_DIR: string;
54
57
  USER_AGENT: string;
@@ -71,6 +74,7 @@ declare const _default: {
71
74
  CLEAN_UP_SNAPSHOT: string;
72
75
  CONTINUS_TEST: string;
73
76
  CONTROL_WORK_DIR: string;
77
+ CHROMIUM_BINARY: string;
74
78
  DEVICE: string;
75
79
  DISABLE_WEB_SECURITY: string;
76
80
  DISABLE_XVFB: string;
@@ -84,6 +88,7 @@ declare const _default: {
84
88
  LEAK_FILTER: string;
85
89
  LOCAL_PUPPETEER: string;
86
90
  LOG_SCRIPT: string;
91
+ MAX_CLUSTER_SAMPLE_SIZE: string;
87
92
  ML_CLUSTERING: string;
88
93
  ML_CLUSTERING_MAX_DF: string;
89
94
  ML_LINKAGE_MAX_DIST: string;
@@ -106,6 +111,7 @@ declare const _default: {
106
111
  SNAPSHOT_DIR: string;
107
112
  TARGET: string;
108
113
  TRACE_ALL_OBJECTS: string;
114
+ TRACE_CONTAINS: string;
109
115
  TRACE_OBJECT_SIZE_ABOVE: string;
110
116
  TREATMENT_WORK_DIR: string;
111
117
  USER_AGENT: string;
@@ -16,6 +16,7 @@ const optionNames = {
16
16
  CLEAN_UP_SNAPSHOT: 'clean-up-snapshot',
17
17
  CONTINUS_TEST: 'ContinuousTest',
18
18
  CONTROL_WORK_DIR: 'control-work-dir',
19
+ CHROMIUM_BINARY: 'chromium-binary',
19
20
  DEVICE: 'device',
20
21
  DISABLE_WEB_SECURITY: 'disable-web-security',
21
22
  DISABLE_XVFB: 'disable-xvfb',
@@ -29,6 +30,7 @@ const optionNames = {
29
30
  LEAK_FILTER: 'leak-filter',
30
31
  LOCAL_PUPPETEER: 'local-puppeteer',
31
32
  LOG_SCRIPT: 'log-script',
33
+ MAX_CLUSTER_SAMPLE_SIZE: 'max-cluster-sample-size',
32
34
  ML_CLUSTERING: 'ml-clustering',
33
35
  ML_CLUSTERING_MAX_DF: 'ml-clustering-max-df',
34
36
  ML_LINKAGE_MAX_DIST: 'ml-linkage-max-dist',
@@ -51,6 +53,7 @@ const optionNames = {
51
53
  SNAPSHOT_DIR: 'snapshot-dir',
52
54
  TARGET: 'target',
53
55
  TRACE_ALL_OBJECTS: 'trace-all-objects',
56
+ TRACE_CONTAINS: 'trace-contains',
54
57
  TRACE_OBJECT_SIZE_ABOVE: 'trace-object-size-above',
55
58
  TREATMENT_WORK_DIR: 'treatment-work-dir',
56
59
  USER_AGENT: 'user-agent',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memlab/cli",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "license": "MIT",
5
5
  "description": "command line interface for memlab",
6
6
  "author": "Liang Gong <lgong@fb.com>",