Skip to content

Commit 78683db

Browse files
committed
build: update UA validation script
With this change we update the UA usage script to read schemas directly insteads of relying on JSON help.
1 parent 29c2b3a commit 78683db

File tree

1 file changed

+28
-57
lines changed

1 file changed

+28
-57
lines changed

scripts/validate-user-analytics.ts

Lines changed: 28 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,22 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { analytics, logging, tags } from '@angular-devkit/core';
10-
import { spawnSync } from 'child_process';
9+
import { analytics, logging, schema, strings, tags } from '@angular-devkit/core';
1110
import * as fs from 'fs';
12-
import * as os from 'os';
11+
import { glob as globCb } from 'glob';
1312
import * as path from 'path';
14-
import { CommandDescriptionMap, Option } from '../packages/angular/cli/models/interface';
15-
import create from './create';
13+
import { promisify } from 'util';
14+
import { packages } from '../lib/packages';
1615

1716
const userAnalyticsTable = require('./templates/user-analytics-table').default;
1817

1918
const dimensionsTableRe = /<!--DIMENSIONS_TABLE_BEGIN-->([\s\S]*)<!--DIMENSIONS_TABLE_END-->/m;
2019
const metricsTableRe = /<!--METRICS_TABLE_BEGIN-->([\s\S]*)<!--METRICS_TABLE_END-->/m;
2120

22-
/**
23-
* Execute a command.
24-
* @private
25-
*/
26-
function _exec(command: string, args: string[], opts: { cwd?: string }, logger: logging.Logger) {
27-
const { status, error, stdout } = spawnSync(command, args, {
28-
stdio: ['ignore', 'pipe', 'inherit'],
29-
...opts,
30-
});
31-
32-
if (status != 0) {
33-
logger.error(`Command failed: ${command} ${args.map((x) => JSON.stringify(x)).join(', ')}`);
34-
throw error;
35-
}
36-
37-
return stdout.toString('utf-8');
38-
}
39-
4021
async function _checkDimensions(dimensionsTable: string, logger: logging.Logger) {
4122
const data: { userAnalytics: number; type: string; name: string }[] = new Array(200);
4223

43-
function _updateData(userAnalytics: number, name: string, type: string) {
24+
function updateData(userAnalytics: number, name: string, type: string) {
4425
if (data[userAnalytics]) {
4526
if (data[userAnalytics].name !== name) {
4627
logger.error(tags.stripIndents`
@@ -77,47 +58,37 @@ async function _checkDimensions(dimensionsTable: string, logger: logging.Logger)
7758
`Invalid value found in enum AnalyticsDimensions: ${JSON.stringify(userAnalytics)}`,
7859
);
7960
}
80-
_updateData(userAnalytics, flagName, type);
61+
updateData(userAnalytics, flagName, type);
8162
}
8263

83-
// Creating a new project and reading the help.
84-
logger.info('Creating temporary project for gathering help...');
85-
86-
const newProjectTempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'angular-cli-create-'));
87-
const newProjectName = 'help-project';
88-
const newProjectRoot = path.join(newProjectTempRoot, newProjectName);
89-
await create({ _: [newProjectName] }, logger.createChild('create'), newProjectTempRoot);
64+
logger.info('Gathering options for user-analytics...');
9065

91-
const commandDescription: CommandDescriptionMap = {};
66+
const userAnalyticsGatherer = (obj: Object) => {
67+
for (const [key, value] of Object.entries(obj)) {
68+
if (value && typeof value === 'object') {
69+
if ('x-user-analytics' in value) {
70+
const type =
71+
[...schema.getTypesOfSchema(value)].find((type) => type !== 'object') ?? 'string';
9272

93-
logger.info('Gathering options...');
94-
95-
const commands = require('../packages/angular/cli/commands.json');
96-
const ngPath = path.join(newProjectRoot, 'node_modules/.bin/ng');
97-
for (const commandName of Object.keys(commands)) {
98-
const options = { cwd: newProjectRoot };
99-
const childLogger = logger.createChild(commandName);
100-
const stdout = _exec(ngPath, [commandName, '--help=json'], options, childLogger);
101-
commandDescription[commandName] = JSON.parse(stdout.trim());
102-
}
103-
104-
function _checkOptionsForAnalytics(options: Option[]) {
105-
for (const option of options) {
106-
if (option.subcommands) {
107-
for (const subcommand of Object.values(option.subcommands)) {
108-
_checkOptionsForAnalytics(subcommand.options);
73+
updateData(value['x-user-analytics'], 'Flag: --' + strings.dasherize(key), type);
74+
} else {
75+
userAnalyticsGatherer(value);
10976
}
11077
}
111-
112-
if (option.userAnalytics === undefined) {
113-
continue;
114-
}
115-
_updateData(option.userAnalytics, 'Flag: --' + option.name, option.type);
11678
}
117-
}
79+
};
80+
81+
const glob = promisify(globCb);
11882

119-
for (const commandName of Object.keys(commandDescription)) {
120-
_checkOptionsForAnalytics(commandDescription[commandName].options);
83+
// Find all the schemas
84+
const packagesPaths = Object.values(packages).map(({ root }) => root);
85+
for (const packagePath of packagesPaths) {
86+
const schemasPaths = await glob('**/schema.json', { cwd: packagePath });
87+
88+
for (const schemaPath of schemasPaths) {
89+
const schema = await fs.promises.readFile(path.join(packagePath, schemaPath), 'utf8');
90+
userAnalyticsGatherer(JSON.parse(schema));
91+
}
12192
}
12293

12394
const generatedTable = userAnalyticsTable({ flags: data }).trim();

0 commit comments

Comments
 (0)