-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathflagUtils.ts
More file actions
117 lines (102 loc) · 3.42 KB
/
flagUtils.ts
File metadata and controls
117 lines (102 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type {cliOptions} from '../bin/chrome-devtools-mcp-cli-options.js';
import {toSnakeCase} from '../utils/string.js';
import type {FlagUsage} from './types.js';
type CliOptions = typeof cliOptions;
/**
* For enums, log the value as uppercase.
* We're going to have an enum for such flags with choices represented
* as an `enum` where the keys of the enum will map to the uppercase `choice`.
*/
function formatEnumChoice(snakeCaseName: string, choice: string): string {
return `${snakeCaseName}_${choice}`.toUpperCase();
}
/**
* Computes telemetry flag usage from parsed arguments and CLI options.
*
* Iterates over the defined CLI options to construct a payload:
* - Flag names are converted to snake_case (e.g. `browserUrl` -> `browser_url`).
* - A flag is logged as `{flag_name}_present` if:
* - It has no default value, OR
* - The provided value differs from the default value.
* - Boolean flags are logged with their literal value.
* - String flags with defined `choices` (Enums) are logged as their uppercase value.
*
* IMPORTANT: keep getPossibleFlagMetrics() in sync with this function.
*/
export function computeFlagUsage(
args: Record<string, unknown>,
options: CliOptions,
): FlagUsage {
const usage: FlagUsage = {};
for (const [flagName, config] of Object.entries(options)) {
const value = args[flagName];
const snakeCaseName = toSnakeCase(flagName);
// If there isn't a default value provided for the flag,
// we're going to log whether it's present on the args user
// provided or not. If there is a default value, we only log presence
// if the value differs from the default, implying explicit user intent.
if (!('default' in config) || value !== config.default) {
usage[`${snakeCaseName}_present`] = value !== undefined && value !== null;
}
if (config.type === 'boolean' && typeof value === 'boolean') {
// For boolean options, we're going to log the value directly.
usage[snakeCaseName] = value;
} else if (
config.type === 'string' &&
typeof value === 'string' &&
'choices' in config &&
config.choices
) {
usage[snakeCaseName] = formatEnumChoice(snakeCaseName, value);
}
}
return usage;
}
export interface FlagMetric {
name: string;
flagType: 'boolean' | 'enum';
choices?: string[];
}
/**
* Computes the list of possible flag metrics based on the CLI options.
*
* IMPORTANT: keep this function in sync with computeFlagUsage().
*/
export function getPossibleFlagMetrics(options: CliOptions): FlagMetric[] {
const metrics: FlagMetric[] = [];
for (const [flagName, config] of Object.entries(options)) {
const snakeCaseName = toSnakeCase(flagName);
// _present is always a possible metric
metrics.push({
name: `${snakeCaseName}_present`,
flagType: 'boolean',
});
if (config.type === 'boolean') {
metrics.push({
name: snakeCaseName,
flagType: 'boolean',
});
} else if (
config.type === 'string' &&
'choices' in config &&
config.choices
) {
metrics.push({
name: snakeCaseName,
flagType: 'enum',
choices: [
`${snakeCaseName.toUpperCase()}_UNSPECIFIED`,
...config.choices.map(choice =>
formatEnumChoice(snakeCaseName, choice),
),
],
});
}
}
return metrics;
}