@memlab/cli 1.0.19 → 1.0.21

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/bin/memlab.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env -S node --expose-gc --max-old-space-size=4096
1
+ #!/usr/bin/env node --expose-gc --max-old-space-size=4096
2
2
 
3
3
  /**
4
4
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -44,6 +44,7 @@ const NumberOfRunsOption_1 = __importDefault(require("../options/NumberOfRunsOpt
44
44
  const HeadfulBrowserOption_1 = __importDefault(require("../options/e2e/HeadfulBrowserOption"));
45
45
  const DisableWebSecurityOption_1 = __importDefault(require("../options/e2e/DisableWebSecurityOption"));
46
46
  const EnableJSRewriteOption_1 = __importDefault(require("../options/e2e/EnableJSRewriteOption"));
47
+ const EnableJSInterceptOption_1 = __importDefault(require("../options/e2e/EnableJSInterceptOption"));
47
48
  class RunMeasureCommand extends BaseCommand_1.default {
48
49
  getCommandName() {
49
50
  return 'measure';
@@ -81,6 +82,7 @@ class RunMeasureCommand extends BaseCommand_1.default {
81
82
  new DisableXvfbOption_1.default(),
82
83
  new DisableWebSecurityOption_1.default(),
83
84
  new EnableJSRewriteOption_1.default(),
85
+ new EnableJSInterceptOption_1.default(),
84
86
  ];
85
87
  }
86
88
  run(options) {
@@ -37,6 +37,7 @@ const CheckXvfbSupportCommand_1 = __importDefault(require("./snapshot/CheckXvfbS
37
37
  const HeadfulBrowserOption_1 = __importDefault(require("../options/e2e/HeadfulBrowserOption"));
38
38
  const DisableWebSecurityOption_1 = __importDefault(require("../options/e2e/DisableWebSecurityOption"));
39
39
  const EnableJSRewriteOption_1 = __importDefault(require("../options/e2e/EnableJSRewriteOption"));
40
+ const EnableJSInterceptOption_1 = __importDefault(require("../options/e2e/EnableJSInterceptOption"));
40
41
  class FBWarmupAppCommand extends BaseCommand_1.default {
41
42
  getCommandName() {
42
43
  return 'warmup';
@@ -67,6 +68,7 @@ class FBWarmupAppCommand extends BaseCommand_1.default {
67
68
  new DisableWebSecurityOption_1.default(),
68
69
  new SkipWarmupOption_1.default(),
69
70
  new EnableJSRewriteOption_1.default(),
71
+ new EnableJSInterceptOption_1.default(),
70
72
  ];
71
73
  }
72
74
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -85,7 +85,13 @@ class CliScreen {
85
85
  initCallbacks(controller, screen) {
86
86
  const selectDebounce = (0, HeapViewUtils_1.debounce)(150);
87
87
  const selectCallback = (componentId, index, content, selectInfo) => {
88
- if (selectInfo.keyName === 'enter') {
88
+ if (selectInfo.keyName === 'd' || selectInfo.keyName === 'D') {
89
+ selectDebounce(() => {
90
+ controller.displaySourceCode(componentId, index);
91
+ screen.render();
92
+ });
93
+ }
94
+ else if (selectInfo.keyName === 'enter') {
89
95
  selectDebounce(() => {
90
96
  controller.setCurrentHeapObjectFromComponent(componentId, index);
91
97
  screen.render();
@@ -161,6 +167,7 @@ class CliScreen {
161
167
  }
162
168
  initClusteredObjectBox(callbacks) {
163
169
  const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getClusteredObjectBoxSize()));
170
+ box.setController(this.heapController);
164
171
  box.setFocusKey(this.getNextFocusKey());
165
172
  box.setLabel('Clustered Objects');
166
173
  this.screen.append(box.element);
@@ -177,6 +184,7 @@ class CliScreen {
177
184
  }
178
185
  initReferrerBox(callbacks) {
179
186
  const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getReferrerBoxSize()));
187
+ box.setController(this.heapController);
180
188
  box.setFocusKey(this.getNextFocusKey());
181
189
  box.setLabel('Referrers');
182
190
  this.screen.append(box.element);
@@ -193,6 +201,7 @@ class CliScreen {
193
201
  }
194
202
  initObjectBox(callbacks) {
195
203
  const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getObjectBoxSize()));
204
+ box.setController(this.heapController);
196
205
  box.setFocusKey(this.getNextFocusKey());
197
206
  box.setLabel('Objects');
198
207
  this.screen.append(box.element);
@@ -211,6 +220,7 @@ class CliScreen {
211
220
  }
212
221
  initObjectPropertyBox(callbacks) {
213
222
  const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getObjectPropertyBoxSize()));
223
+ box.setController(this.heapController);
214
224
  box.setFocusKey(this.getNextFocusKey());
215
225
  box.setLabel('Objects Detail');
216
226
  this.screen.append(box.element);
@@ -229,6 +239,7 @@ class CliScreen {
229
239
  }
230
240
  initReferenceBox(callbacks) {
231
241
  const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getReferenceBoxSize()));
242
+ box.setController(this.heapController);
232
243
  box.setFocusKey(this.getNextFocusKey());
233
244
  box.setLabel('References');
234
245
  this.screen.append(box.element);
@@ -246,6 +257,7 @@ class CliScreen {
246
257
  }
247
258
  initRetainerTraceBox(callbacks) {
248
259
  const box = new ListComponent_1.default([], callbacks, Object.assign({}, this.getRetainerTraceBoxSize()));
260
+ box.setController(this.heapController);
249
261
  box.setFocusKey(this.getNextFocusKey());
250
262
  box.setLabel('Retainer Trace');
251
263
  this.screen.append(box.element);
@@ -1,13 +1,4 @@
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 { IHeapSnapshot, IHeapNode } from '@memlab/core';
1
+ import type { IHeapSnapshot, IHeapNode, Nullable } from '@memlab/core';
11
2
  import type ListComponent from './ListComponent';
12
3
  import { ComponentDataItem, ComponentData } from './HeapViewUtils';
13
4
  declare type SelectHeapObjectOption = {
@@ -37,11 +28,13 @@ export default class HeapViewController {
37
28
  private referenceBox;
38
29
  private objectPropertyBox;
39
30
  private retainerTracePropertyBox;
31
+ private scriptManager;
40
32
  constructor(heap: IHeapSnapshot, objectCategory: ObjectCategory);
41
33
  private getFlattenHeapObjectsInfo;
42
34
  private getFlattenClusteredObjectsInfo;
43
35
  private shouldClusterCategory;
44
36
  private clusterComponentDataItems;
37
+ getComponentDataById(componentId: number): Nullable<ComponentData>;
45
38
  getContent(componentId: number): string[];
46
39
  setClusteredBox(component: ListComponent): void;
47
40
  getClusteredBoxData(): ComponentData;
@@ -59,6 +52,10 @@ export default class HeapViewController {
59
52
  private getKeyValuePairString;
60
53
  setRetainerTraceBox(component: ListComponent): void;
61
54
  getRetainerTraceData(): ComponentData;
55
+ private getHeapObject;
56
+ displaySourceCode(componentId: number, itemIndex: number): void;
57
+ private displayClosureInfo;
58
+ private getClosureNodeScopeVarEdges;
62
59
  setCurrentHeapObjectFromComponent(componentId: number, itemIndex: number, options?: {
63
60
  skipFocus?: boolean;
64
61
  }): void;
@@ -3,8 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
6
7
  const chalk_1 = __importDefault(require("chalk"));
8
+ const worker_threads_1 = require("worker_threads");
7
9
  const core_1 = require("@memlab/core");
10
+ const e2e_1 = require("@memlab/e2e");
8
11
  const HeapViewUtils_1 = require("./HeapViewUtils");
9
12
  /**
10
13
  * HeapViewController managers all the data associated with each
@@ -21,6 +24,8 @@ class HeapViewController {
21
24
  this.currentHeapObject = (0, HeapViewUtils_1.getHeapObjectAt)(this.currentHeapObjectsInfo, 0);
22
25
  this.componentIdToDataMap = new Map();
23
26
  this.componentIdToComponentMap = new Map();
27
+ this.scriptManager = new e2e_1.ScriptManager();
28
+ this.scriptManager.loadFromFiles();
24
29
  }
25
30
  getFlattenHeapObjectsInfo(objectCategory) {
26
31
  let ret = [];
@@ -66,6 +71,10 @@ class HeapViewController {
66
71
  });
67
72
  return ret;
68
73
  }
74
+ getComponentDataById(componentId) {
75
+ var _a;
76
+ return (_a = this.componentIdToDataMap.get(componentId)) !== null && _a !== void 0 ? _a : null;
77
+ }
69
78
  getContent(componentId) {
70
79
  const ret = [];
71
80
  const data = this.componentIdToDataMap.get(componentId);
@@ -178,12 +187,6 @@ class HeapViewController {
178
187
  // if the node has associated location info
179
188
  const location = node.location;
180
189
  if (location) {
181
- const url = core_1.utils.getClosureSourceUrl(node);
182
- if (url) {
183
- data.items.push({
184
- stringContent: this.getKeyValuePairString('code link', url),
185
- });
186
- }
187
190
  data.items.push({
188
191
  stringContent: this.getKeyValuePairString('script id', location.script_id),
189
192
  });
@@ -215,16 +218,18 @@ class HeapViewController {
215
218
  });
216
219
  }
217
220
  if (node.type === 'closure') {
218
- const contextNode = node.getReferenceNode('context', 'internal');
219
- if (contextNode) {
220
- contextNode.forEachReference(edge => {
221
- data.items.push({
222
- tag: chalk_1.default.grey('Scope Variable'),
223
- referrerEdge: edge,
224
- heapObject: edge.toNode,
225
- });
221
+ const url = core_1.utils.getClosureSourceUrl(node);
222
+ if (url) {
223
+ data.items.push({
224
+ stringContent: this.getKeyValuePairString('code link', url),
226
225
  });
227
226
  }
227
+ const closureVars = this.getClosureNodeScopeVarEdges(node);
228
+ closureVars.forEach(edge => data.items.push({
229
+ tag: chalk_1.default.grey('Outer Scope Var'),
230
+ referrerEdge: edge,
231
+ heapObject: edge.toNode,
232
+ }));
228
233
  }
229
234
  data.selectedIdx = data.items.length > 0 ? 0 : -1;
230
235
  return data;
@@ -261,33 +266,79 @@ class HeapViewController {
261
266
  data.selectedIdx = data.items.length > 0 ? 0 : -1;
262
267
  return data;
263
268
  }
264
- setCurrentHeapObjectFromComponent(componentId, itemIndex, options = {}) {
269
+ getHeapObject(componentId, itemIndex) {
265
270
  const data = this.componentIdToDataMap.get(componentId);
266
271
  if (!data) {
267
- return;
272
+ return null;
268
273
  }
269
274
  const item = data.items[itemIndex];
270
275
  if (!item) {
271
- return;
276
+ return null;
272
277
  }
273
278
  const heapObject = item.heapObject;
274
279
  if (!heapObject) {
280
+ return null;
281
+ }
282
+ return heapObject;
283
+ }
284
+ displaySourceCode(componentId, itemIndex) {
285
+ const node = this.getHeapObject(componentId, itemIndex);
286
+ if (node && node.type === 'closure') {
287
+ this.displayClosureInfo(node);
288
+ }
289
+ }
290
+ // locate and display source code of a closure node
291
+ // in a worker thread
292
+ displayClosureInfo(node) {
293
+ const url = core_1.utils.getClosureSourceUrl(node);
294
+ if (!url) {
275
295
  return;
276
296
  }
277
- this.setCurrentHeapObject(heapObject, options);
297
+ const closureVars = this.getClosureNodeScopeVarEdges(node).map(edge => `${edge.name_or_index}`);
298
+ const workerData = {
299
+ url,
300
+ closureVars,
301
+ };
302
+ new worker_threads_1.Worker(path_1.default.join(__dirname, '..', 'worker', 'LocateClosureSourceWorker.js'), { workerData });
303
+ }
304
+ getClosureNodeScopeVarEdges(node) {
305
+ const internalReferences = new Set(['map', 'scope_info', 'previous']);
306
+ const contextNode = node.getReferenceNode('context', 'internal');
307
+ const ret = [];
308
+ if (contextNode) {
309
+ contextNode.forEachReference(edge => {
310
+ const name = `${edge.name_or_index}`;
311
+ if (!internalReferences.has(name)) {
312
+ ret.push(edge);
313
+ }
314
+ });
315
+ }
316
+ return ret;
317
+ }
318
+ setCurrentHeapObjectFromComponent(componentId, itemIndex, options = {}) {
319
+ const heapObject = this.getHeapObject(componentId, itemIndex);
320
+ if (heapObject) {
321
+ this.setCurrentHeapObject(heapObject, options);
322
+ }
278
323
  }
279
324
  setCurrentHeapObject(node, options = {}) {
280
325
  this.currentHeapObject = node;
281
- // set parent box's data and content
326
+ // set clustered box's data and content
282
327
  const clusteredBoxData = this.getClusteredBoxData();
283
328
  this.componentIdToDataMap.set(this.clusteredBox.id, clusteredBoxData);
284
329
  this.clusteredBox.setContent(this.getContent(this.clusteredBox.id));
285
330
  this.clusteredBox.selectIndex(clusteredBoxData.selectedIdx);
331
+ // must set label here again so the additional label info
332
+ // can render with updated component data
333
+ this.clusteredBox.setLabel('Clustered Objects');
286
334
  // set object box's data and content
287
335
  const objectBoxData = this.getObjectBoxData();
288
336
  this.componentIdToDataMap.set(this.objectBox.id, objectBoxData);
289
337
  this.objectBox.setContent(this.getContent(this.objectBox.id));
290
338
  this.objectBox.selectIndex(objectBoxData.selectedIdx);
339
+ // must set label here again so the additional label info
340
+ // can render with updated component data
341
+ this.objectBox.setLabel('Objects');
291
342
  this.setSelectedHeapObject(node);
292
343
  if (!options.skipFocus) {
293
344
  this.focusOnComponent(this.objectBox.id);
@@ -8,6 +8,7 @@
8
8
  * @oncall web_perf_infra
9
9
  */
10
10
  import type { Widgets } from 'blessed';
11
+ import type HeapViewController from './HeapViewController';
11
12
  export declare type ListComponentOption = {
12
13
  width: number;
13
14
  height: number;
@@ -18,6 +19,9 @@ export declare type ListComponentOption = {
18
19
  export declare type ListItemSelectInfo = {
19
20
  keyName: string;
20
21
  };
22
+ export declare type LabelOption = {
23
+ nextTick?: boolean;
24
+ };
21
25
  export declare type ListCallbacks = {
22
26
  selectCallback?: (componentId: number, index: number, content: string[], selectInfo: ListItemSelectInfo) => void;
23
27
  updateContent?: (oldContent: string[], newContent: string[]) => void;
@@ -32,6 +36,8 @@ export declare type ListCallbacks = {
32
36
  export default class ListComponent {
33
37
  element: Widgets.ListElement;
34
38
  id: number;
39
+ private labelText;
40
+ private controller;
35
41
  private listIndex;
36
42
  private content;
37
43
  private callbacks;
@@ -44,6 +50,7 @@ export default class ListComponent {
44
50
  private static nextComponentId;
45
51
  private static nextId;
46
52
  constructor(content: string[], callbacks: ListCallbacks, options: ListComponentOption);
53
+ setController(controller: HeapViewController): void;
47
54
  private render;
48
55
  private static createEntryForMore;
49
56
  protected registerKeys(): void;
@@ -53,7 +60,7 @@ export default class ListComponent {
53
60
  loseFocus(): void;
54
61
  selectIndex(index: number): void;
55
62
  setFocusKey(key: string): void;
56
- setLabel(label: string): void;
63
+ setLabel(label: string, option?: LabelOption): void;
57
64
  setContent(content: string[]): void;
58
65
  loadMoreContent(): void;
59
66
  private removeDisplayMoreEntry;
@@ -14,6 +14,8 @@ const HeapViewUtils_1 = require("./HeapViewUtils");
14
14
  */
15
15
  class ListComponent {
16
16
  constructor(content, callbacks, options) {
17
+ this.labelText = '';
18
+ this.controller = null;
17
19
  this.listIndex = 0;
18
20
  this.content = [];
19
21
  this.moreEntryIndex = -1;
@@ -41,6 +43,9 @@ class ListComponent {
41
43
  static nextId() {
42
44
  return ListComponent.nextComponentId++;
43
45
  }
46
+ setController(controller) {
47
+ this.controller = controller;
48
+ }
44
49
  // render the whole screen
45
50
  render() {
46
51
  if (this.callbacks.render) {
@@ -64,6 +69,12 @@ class ListComponent {
64
69
  self.loadMoreContent();
65
70
  return;
66
71
  }
72
+ // if press 'd'
73
+ if (key.name === 'd' || key.name === 'D') {
74
+ self.selectUpdate(self.listIndex, content, {
75
+ keyName: key.name,
76
+ });
77
+ }
67
78
  // move selection down
68
79
  if (key.name === 'down' && self.listIndex < self.displayedItems - 1) {
69
80
  self.element.select(++self.listIndex);
@@ -160,9 +171,23 @@ class ListComponent {
160
171
  setFocusKey(key) {
161
172
  this.focusKey = key;
162
173
  }
163
- setLabel(label) {
164
- const componentLabel = label + chalk_1.default.grey(` (press ${chalk_1.default.inverse(this.focusKey)} to focus)`);
165
- this.element.setLabel(componentLabel);
174
+ setLabel(label, option = {}) {
175
+ this.labelText = label;
176
+ let componentLabel = label + chalk_1.default.grey(` (press ${chalk_1.default.inverse(this.focusKey)} to focus)`);
177
+ if (this.controller) {
178
+ const data = this.controller.getComponentDataById(this.id);
179
+ if (data) {
180
+ componentLabel += chalk_1.default.grey(` ${data.items.length} items`);
181
+ }
182
+ }
183
+ if (option.nextTick) {
184
+ process.nextTick(() => {
185
+ this.element.setLabel(componentLabel);
186
+ });
187
+ }
188
+ else {
189
+ this.element.setLabel(componentLabel);
190
+ }
166
191
  }
167
192
  setContent(content) {
168
193
  const oldContent = this.content;
@@ -0,0 +1,11 @@
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
+ export {};
11
+ //# sourceMappingURL=LocateClosureSourceWorker.d.ts.map
@@ -0,0 +1,69 @@
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 fs_1 = __importDefault(require("fs"));
25
+ const worker_threads_1 = require("worker_threads");
26
+ const core_1 = require("@memlab/core");
27
+ const e2e_1 = require("@memlab/e2e");
28
+ if (!worker_threads_1.isMainThread) {
29
+ try {
30
+ displaySourceCode();
31
+ }
32
+ catch (ex) {
33
+ // do nothing
34
+ }
35
+ }
36
+ function displaySourceCode() {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ const scriptManager = new e2e_1.ScriptManager();
39
+ scriptManager.loadFromFiles();
40
+ const { url, closureVars } = worker_threads_1.workerData;
41
+ const code = scriptManager.loadCodeForUrl(url);
42
+ const scope = scriptManager.getClosureScopeTreeForUrl(url);
43
+ if (!code || !scope) {
44
+ return;
45
+ }
46
+ const file = core_1.fileManager.getDebugSourceFile();
47
+ fs_1.default.writeFileSync(file, code, 'UTF-8');
48
+ iterateClosures(scope, closureScope => {
49
+ const varSet = new Set(closureScope.variablesDefined);
50
+ const found = closureVars.reduce((acc, v) => varSet.has(v) && acc, true);
51
+ if (found && closureScope.loc) {
52
+ const startLine = closureScope.loc.start.line;
53
+ core_1.utils.runShell(`code -g ${file}:${startLine}`, { disconnectStdio: true });
54
+ }
55
+ return found;
56
+ });
57
+ });
58
+ }
59
+ function iterateClosures(scope, callback) {
60
+ if (callback(scope)) {
61
+ return true;
62
+ }
63
+ for (const subScope of scope.nestedClosures) {
64
+ if (iterateClosures(subScope, callback)) {
65
+ return true;
66
+ }
67
+ }
68
+ return false;
69
+ }
@@ -43,6 +43,7 @@ const HeadfulBrowserOption_1 = __importDefault(require("../../options/e2e/Headfu
43
43
  const SetUserAgentOption_1 = __importDefault(require("../../options/e2e/SetUserAgentOption"));
44
44
  const DisableWebSecurityOption_1 = __importDefault(require("../../options/e2e/DisableWebSecurityOption"));
45
45
  const EnableJSRewriteOption_1 = __importDefault(require("../../options/e2e/EnableJSRewriteOption"));
46
+ const EnableJSInterceptOption_1 = __importDefault(require("../../options/e2e/EnableJSInterceptOption"));
46
47
  class TakeSnapshotCommand extends BaseCommand_1.default {
47
48
  getCommandName() {
48
49
  return 'snapshot';
@@ -83,6 +84,7 @@ class TakeSnapshotCommand extends BaseCommand_1.default {
83
84
  new DisableXvfbOption_1.default(),
84
85
  new DisableWebSecurityOption_1.default(),
85
86
  new EnableJSRewriteOption_1.default(),
87
+ new EnableJSInterceptOption_1.default(),
86
88
  ];
87
89
  }
88
90
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1,3 +1,12 @@
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
+ */
1
10
  export declare const OptionNames: {
2
11
  DEBUG: string;
3
12
  HELP: string;
@@ -1,4 +1,13 @@
1
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
+ */
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.OptionShortcuts = exports.OptionNames = void 0;
4
13
  exports.OptionNames = {
@@ -28,7 +28,7 @@ class HeadfulBrowserOption extends core_1.BaseOption {
28
28
  return OptionConstant_1.default.optionNames.HEADFUL;
29
29
  }
30
30
  getDescription() {
31
- return 'start the browser in headful mode, but default it is headless';
31
+ return 'start the browser in headful mode, by default it is headless';
32
32
  }
33
33
  parse(config, args) {
34
34
  return __awaiter(this, void 0, void 0, function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memlab/cli",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "license": "MIT",
5
5
  "description": "command line interface for memlab",
6
6
  "author": "Liang Gong <lgong@fb.com>",
@@ -60,7 +60,7 @@
60
60
  "scripts": {
61
61
  "preinstall": "node bin/preinstall",
62
62
  "build-pkg": "tsc",
63
- "publish-patch": "npm version patch --force && npm publish",
63
+ "publish-patch": "npm publish",
64
64
  "clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo"
65
65
  },
66
66
  "bugs": {