@rindo/core 2.16.1 → 2.17.1
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/cli/config-flags.d.ts +102 -0
- package/cli/index.cjs +690 -223
- package/cli/index.d.ts +2 -1
- package/cli/index.js +690 -223
- package/cli/package.json +1 -1
- package/compiler/package.json +1 -1
- package/compiler/rindo.js +856 -289
- package/compiler/rindo.min.js +2 -2
- package/dependencies.json +1 -1
- package/dev-server/client/index.js +1 -1
- package/dev-server/client/package.json +1 -1
- package/dev-server/connector.html +2 -2
- package/dev-server/index.js +1 -1
- package/dev-server/package.json +1 -1
- package/dev-server/server-process.js +2 -2
- package/internal/app-data/package.json +1 -1
- package/internal/client/css-shim.js +1 -1
- package/internal/client/dom.js +1 -1
- package/internal/client/index.js +11 -6
- package/internal/client/package.json +1 -1
- package/internal/client/patch-browser.js +1 -1
- package/internal/client/patch-esm.js +1 -1
- package/internal/client/shadow-css.js +1 -1
- package/internal/hydrate/index.js +2 -2
- package/internal/hydrate/package.json +1 -1
- package/internal/package.json +1 -1
- package/internal/rindo-private.d.ts +6 -2
- package/internal/rindo-public-compiler.d.ts +67 -48
- package/internal/testing/index.js +1 -1
- package/internal/testing/package.json +1 -1
- package/mock-doc/index.cjs +140 -5
- package/mock-doc/index.d.ts +76 -1
- package/mock-doc/index.js +140 -5
- package/mock-doc/package.json +1 -1
- package/package.json +5 -3
- package/screenshot/package.json +1 -1
- package/sys/node/index.js +325 -314
- package/sys/node/package.json +1 -1
- package/sys/node/worker.js +1 -1
- package/testing/index.d.ts +1 -1
- package/testing/index.js +124 -69
- package/testing/jest/jest-config.d.ts +1 -1
- package/testing/jest/jest-runner.d.ts +3 -2
- package/testing/jest/jest-screenshot.d.ts +1 -1
- package/testing/mocks.d.ts +48 -3
- package/testing/package.json +1 -1
- package/testing/puppeteer/puppeteer-browser.d.ts +2 -2
- package/testing/testing-utils.d.ts +74 -2
- package/testing/testing.d.ts +2 -2
package/cli/index.js
CHANGED
|
@@ -1,8 +1,50 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
Rindo CLI v2.
|
|
2
|
+
Rindo CLI v2.17.1 | MIT Licensed | https://rindojs.web.app
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* This sets the log level hierarchy for our terminal logger, ranging from
|
|
6
|
+
* most to least verbose.
|
|
7
|
+
*
|
|
8
|
+
* Ordering the levels like this lets us easily check whether we should log a
|
|
9
|
+
* message at a given time. For instance, if the log level is set to `'warn'`,
|
|
10
|
+
* then anything passed to the logger with level `'warn'` or `'error'` should
|
|
11
|
+
* be logged, but we should _not_ log anything with level `'info'` or `'debug'`.
|
|
12
|
+
*
|
|
13
|
+
* If we have a current log level `currentLevel` and a message with level
|
|
14
|
+
* `msgLevel` is passed to the logger, we can determine whether or not we should
|
|
15
|
+
* log it by checking if the log level on the message is further up or at the
|
|
16
|
+
* same level in the hierarchy than `currentLevel`, like so:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* LOG_LEVELS.indexOf(msgLevel) >= LOG_LEVELS.indexOf(currentLevel)
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* NOTE: for the reasons described above, do not change the order of the entries
|
|
23
|
+
* in this array without good reason!
|
|
24
|
+
*/
|
|
25
|
+
const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Convert a string from PascalCase to dash-case
|
|
29
|
+
*
|
|
30
|
+
* @param str the string to convert
|
|
31
|
+
* @returns a converted string
|
|
32
|
+
*/
|
|
33
|
+
const toDashCase = (str) => str
|
|
34
|
+
.replace(/([A-Z0-9])/g, (match) => ` ${match[0]}`)
|
|
35
|
+
.trim()
|
|
36
|
+
.split(' ')
|
|
37
|
+
.join('-')
|
|
38
|
+
.toLowerCase();
|
|
39
|
+
/**
|
|
40
|
+
* Convert a string from dash-case / kebab-case to PascalCase (or CamelCase,
|
|
41
|
+
* or whatever you call it!)
|
|
42
|
+
*
|
|
43
|
+
* @param str a string to convert
|
|
44
|
+
* @returns a converted string
|
|
45
|
+
*/
|
|
46
|
+
const dashToPascalCase = (str) => str
|
|
47
|
+
.toLowerCase()
|
|
6
48
|
.split('-')
|
|
7
49
|
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
8
50
|
.join('');
|
|
@@ -275,22 +317,211 @@ const validateComponentTag = (tag) => {
|
|
|
275
317
|
return undefined;
|
|
276
318
|
};
|
|
277
319
|
|
|
320
|
+
/**
|
|
321
|
+
* All the Boolean options supported by the Rindo CLI
|
|
322
|
+
*/
|
|
323
|
+
const BOOLEAN_CLI_ARGS = [
|
|
324
|
+
'build',
|
|
325
|
+
'cache',
|
|
326
|
+
'checkVersion',
|
|
327
|
+
'ci',
|
|
328
|
+
'compare',
|
|
329
|
+
'debug',
|
|
330
|
+
'dev',
|
|
331
|
+
'devtools',
|
|
332
|
+
'docs',
|
|
333
|
+
'e2e',
|
|
334
|
+
'es5',
|
|
335
|
+
'esm',
|
|
336
|
+
'headless',
|
|
337
|
+
'help',
|
|
338
|
+
'log',
|
|
339
|
+
'open',
|
|
340
|
+
'prerender',
|
|
341
|
+
'prerenderExternal',
|
|
342
|
+
'prod',
|
|
343
|
+
'profile',
|
|
344
|
+
'serviceWorker',
|
|
345
|
+
'screenshot',
|
|
346
|
+
'serve',
|
|
347
|
+
'skipNodeCheck',
|
|
348
|
+
'spec',
|
|
349
|
+
'ssr',
|
|
350
|
+
'stats',
|
|
351
|
+
'updateScreenshot',
|
|
352
|
+
'verbose',
|
|
353
|
+
'version',
|
|
354
|
+
'watch',
|
|
355
|
+
// JEST CLI OPTIONS
|
|
356
|
+
'all',
|
|
357
|
+
'automock',
|
|
358
|
+
'bail',
|
|
359
|
+
// 'cache', Rindo already supports this argument
|
|
360
|
+
'changedFilesWithAncestor',
|
|
361
|
+
// 'ci', Rindo already supports this argument
|
|
362
|
+
'clearCache',
|
|
363
|
+
'clearMocks',
|
|
364
|
+
'collectCoverage',
|
|
365
|
+
'color',
|
|
366
|
+
'colors',
|
|
367
|
+
'coverage',
|
|
368
|
+
// 'debug', Rindo already supports this argument
|
|
369
|
+
'detectLeaks',
|
|
370
|
+
'detectOpenHandles',
|
|
371
|
+
'errorOnDeprecated',
|
|
372
|
+
'expand',
|
|
373
|
+
'findRelatedTests',
|
|
374
|
+
'forceExit',
|
|
375
|
+
'init',
|
|
376
|
+
'injectGlobals',
|
|
377
|
+
'json',
|
|
378
|
+
'lastCommit',
|
|
379
|
+
'listTests',
|
|
380
|
+
'logHeapUsage',
|
|
381
|
+
'noStackTrace',
|
|
382
|
+
'notify',
|
|
383
|
+
'onlyChanged',
|
|
384
|
+
'onlyFailures',
|
|
385
|
+
'passWithNoTests',
|
|
386
|
+
'resetMocks',
|
|
387
|
+
'resetModules',
|
|
388
|
+
'restoreMocks',
|
|
389
|
+
'runInBand',
|
|
390
|
+
'runTestsByPath',
|
|
391
|
+
'showConfig',
|
|
392
|
+
'silent',
|
|
393
|
+
'skipFilter',
|
|
394
|
+
'testLocationInResults',
|
|
395
|
+
'updateSnapshot',
|
|
396
|
+
'useStderr',
|
|
397
|
+
// 'verbose', Rindo already supports this argument
|
|
398
|
+
// 'version', Rindo already supports this argument
|
|
399
|
+
// 'watch', Rindo already supports this argument
|
|
400
|
+
'watchAll',
|
|
401
|
+
'watchman',
|
|
402
|
+
];
|
|
403
|
+
/**
|
|
404
|
+
* All the Number options supported by the Rindo CLI
|
|
405
|
+
*/
|
|
406
|
+
const NUMBER_CLI_ARGS = [
|
|
407
|
+
'port',
|
|
408
|
+
// JEST CLI ARGS
|
|
409
|
+
'maxConcurrency',
|
|
410
|
+
'testTimeout',
|
|
411
|
+
];
|
|
412
|
+
/**
|
|
413
|
+
* All the String options supported by the Rindo CLI
|
|
414
|
+
*/
|
|
415
|
+
const STRING_CLI_ARGS = [
|
|
416
|
+
'address',
|
|
417
|
+
'config',
|
|
418
|
+
'docsApi',
|
|
419
|
+
'docsJson',
|
|
420
|
+
'emulate',
|
|
421
|
+
'root',
|
|
422
|
+
'screenshotConnector',
|
|
423
|
+
// JEST CLI ARGS
|
|
424
|
+
'cacheDirectory',
|
|
425
|
+
'changedSince',
|
|
426
|
+
'collectCoverageFrom',
|
|
427
|
+
// 'config', Rindo already supports this argument
|
|
428
|
+
'coverageDirectory',
|
|
429
|
+
'coverageThreshold',
|
|
430
|
+
'env',
|
|
431
|
+
'filter',
|
|
432
|
+
'globalSetup',
|
|
433
|
+
'globalTeardown',
|
|
434
|
+
'globals',
|
|
435
|
+
'haste',
|
|
436
|
+
'moduleNameMapper',
|
|
437
|
+
'notifyMode',
|
|
438
|
+
'outputFile',
|
|
439
|
+
'preset',
|
|
440
|
+
'prettierPath',
|
|
441
|
+
'resolver',
|
|
442
|
+
'rootDir',
|
|
443
|
+
'runner',
|
|
444
|
+
'testEnvironment',
|
|
445
|
+
'testEnvironmentOptions',
|
|
446
|
+
'testFailureExitCode',
|
|
447
|
+
'testNamePattern',
|
|
448
|
+
'testResultsProcessor',
|
|
449
|
+
'testRunner',
|
|
450
|
+
'testSequencer',
|
|
451
|
+
'testURL',
|
|
452
|
+
'timers',
|
|
453
|
+
'transform',
|
|
454
|
+
// ARRAY ARGS
|
|
455
|
+
'collectCoverageOnlyFrom',
|
|
456
|
+
'coveragePathIgnorePatterns',
|
|
457
|
+
'coverageReporters',
|
|
458
|
+
'moduleDirectories',
|
|
459
|
+
'moduleFileExtensions',
|
|
460
|
+
'modulePathIgnorePatterns',
|
|
461
|
+
'modulePaths',
|
|
462
|
+
'projects',
|
|
463
|
+
'reporters',
|
|
464
|
+
'roots',
|
|
465
|
+
'selectProjects',
|
|
466
|
+
'setupFiles',
|
|
467
|
+
'setupFilesAfterEnv',
|
|
468
|
+
'snapshotSerializers',
|
|
469
|
+
'testMatch',
|
|
470
|
+
'testPathIgnorePatterns',
|
|
471
|
+
'testPathPattern',
|
|
472
|
+
'testRegex',
|
|
473
|
+
'transformIgnorePatterns',
|
|
474
|
+
'unmockedModulePathPatterns',
|
|
475
|
+
'watchPathIgnorePatterns',
|
|
476
|
+
];
|
|
477
|
+
/**
|
|
478
|
+
* All the CLI arguments which may have string or number values
|
|
479
|
+
*
|
|
480
|
+
* `maxWorkers` is an argument which is used both by Rindo _and_ by Jest,
|
|
481
|
+
* which means that we need to support parsing both string and number values.
|
|
482
|
+
*/
|
|
483
|
+
const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
|
|
484
|
+
/**
|
|
485
|
+
* All the LogLevel-type options supported by the Rindo CLI
|
|
486
|
+
*
|
|
487
|
+
* This is a bit silly since there's only one such argument atm,
|
|
488
|
+
* but this approach lets us make sure that we're handling all
|
|
489
|
+
* our arguments in a type-safe way.
|
|
490
|
+
*/
|
|
491
|
+
const LOG_LEVEL_CLI_ARGS = ['logLevel'];
|
|
492
|
+
/**
|
|
493
|
+
* For a small subset of CLI options we support a short alias e.g. `'h'` for `'help'`
|
|
494
|
+
*/
|
|
495
|
+
const CLI_ARG_ALIASES = {
|
|
496
|
+
config: 'c',
|
|
497
|
+
help: 'h',
|
|
498
|
+
port: 'p',
|
|
499
|
+
version: 'v',
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Parse command line arguments into a structured `ConfigFlags` object
|
|
504
|
+
*
|
|
505
|
+
* @param args an array of config flags
|
|
506
|
+
* @param sys an optional compiler system
|
|
507
|
+
* @returns a structured ConfigFlags object
|
|
508
|
+
*/
|
|
278
509
|
const parseFlags = (args, sys) => {
|
|
279
510
|
const flags = {
|
|
280
511
|
task: null,
|
|
281
512
|
args: [],
|
|
282
513
|
knownArgs: [],
|
|
283
|
-
unknownArgs:
|
|
514
|
+
unknownArgs: [],
|
|
284
515
|
};
|
|
285
516
|
// cmd line has more priority over npm scripts cmd
|
|
286
|
-
flags.args = args.slice();
|
|
517
|
+
flags.args = Array.isArray(args) ? args.slice() : [];
|
|
287
518
|
if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
|
|
288
519
|
flags.task = flags.args[0];
|
|
289
520
|
}
|
|
290
|
-
parseArgs(flags, flags.args
|
|
521
|
+
parseArgs(flags, flags.args);
|
|
291
522
|
if (sys && sys.name === 'node') {
|
|
292
523
|
const envArgs = getNpmConfigEnvArgs(sys);
|
|
293
|
-
parseArgs(flags, envArgs
|
|
524
|
+
parseArgs(flags, envArgs);
|
|
294
525
|
envArgs.forEach((envArg) => {
|
|
295
526
|
if (!flags.args.includes(envArg)) {
|
|
296
527
|
flags.args.push(envArg);
|
|
@@ -309,185 +540,230 @@ const parseFlags = (args, sys) => {
|
|
|
309
540
|
return flags;
|
|
310
541
|
};
|
|
311
542
|
/**
|
|
312
|
-
* Parse command line arguments that are
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
543
|
+
* Parse command line arguments that are enumerated in the `config-flags`
|
|
544
|
+
* module. Handles leading dashes on arguments, aliases that are defined for a
|
|
545
|
+
* small number of arguments, and parsing values for non-boolean arguments
|
|
546
|
+
* (e.g. port number for the dev server).
|
|
316
547
|
*
|
|
317
|
-
* @param flags
|
|
318
|
-
* @param args
|
|
319
|
-
* @param knownArgs an array to which all recognized, legal arguments are added
|
|
548
|
+
* @param flags a ConfigFlags object to which parsed arguments will be added
|
|
549
|
+
* @param args an array of command-line arguments to parse
|
|
320
550
|
*/
|
|
321
|
-
const parseArgs = (flags, args
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
551
|
+
const parseArgs = (flags, args) => {
|
|
552
|
+
BOOLEAN_CLI_ARGS.forEach((argName) => parseBooleanArg(flags, args, argName));
|
|
553
|
+
STRING_CLI_ARGS.forEach((argName) => parseStringArg(flags, args, argName));
|
|
554
|
+
NUMBER_CLI_ARGS.forEach((argName) => parseNumberArg(flags, args, argName));
|
|
555
|
+
STRING_NUMBER_CLI_ARGS.forEach((argName) => parseStringNumberArg(flags, args, argName));
|
|
556
|
+
LOG_LEVEL_CLI_ARGS.forEach((argName) => parseLogLevelArg(flags, args, argName));
|
|
557
|
+
};
|
|
558
|
+
/**
|
|
559
|
+
* Parse a boolean CLI argument. For these, we support the following formats:
|
|
560
|
+
*
|
|
561
|
+
* - `--booleanArg`
|
|
562
|
+
* - `--boolean-arg`
|
|
563
|
+
* - `--noBooleanArg`
|
|
564
|
+
* - `--no-boolean-arg`
|
|
565
|
+
*
|
|
566
|
+
* The final two variants should be parsed to a value of `false` on the config
|
|
567
|
+
* object.
|
|
568
|
+
*
|
|
569
|
+
* @param flags the config flags object, while we'll modify
|
|
570
|
+
* @param args our CLI arguments
|
|
571
|
+
* @param configCaseName the argument we want to look at right now
|
|
572
|
+
*/
|
|
573
|
+
const parseBooleanArg = (flags, args, configCaseName) => {
|
|
574
|
+
// we support both dash-case and PascalCase versions of the parameter
|
|
575
|
+
// argName is 'configCase' version which can be found in BOOLEAN_ARG_OPTS
|
|
576
|
+
const alias = CLI_ARG_ALIASES[configCaseName];
|
|
577
|
+
const dashCaseName = toDashCase(configCaseName);
|
|
578
|
+
if (typeof flags[configCaseName] !== 'boolean') {
|
|
579
|
+
flags[configCaseName] = null;
|
|
580
|
+
}
|
|
581
|
+
args.forEach((cmdArg) => {
|
|
582
|
+
let value;
|
|
583
|
+
if (cmdArg === `--${configCaseName}` || cmdArg === `--${dashCaseName}`) {
|
|
584
|
+
value = true;
|
|
327
585
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
flags[flagKey] = true;
|
|
331
|
-
knownArgs.push(cmdArg);
|
|
332
|
-
}
|
|
333
|
-
else if (cmdArg === `--${flagKey}`) {
|
|
334
|
-
flags[flagKey] = true;
|
|
335
|
-
knownArgs.push(cmdArg);
|
|
336
|
-
}
|
|
337
|
-
else if (cmdArg === `--no-${booleanName}`) {
|
|
338
|
-
flags[flagKey] = false;
|
|
339
|
-
knownArgs.push(cmdArg);
|
|
340
|
-
}
|
|
341
|
-
else if (cmdArg === `--no${dashToPascalCase(booleanName)}`) {
|
|
342
|
-
flags[flagKey] = false;
|
|
343
|
-
knownArgs.push(cmdArg);
|
|
344
|
-
}
|
|
345
|
-
else if (alias && cmdArg === `-${alias}`) {
|
|
346
|
-
flags[flagKey] = true;
|
|
347
|
-
knownArgs.push(cmdArg);
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
STRING_ARG_OPTS.forEach((stringName) => {
|
|
352
|
-
const alias = ARG_OPTS_ALIASES[stringName];
|
|
353
|
-
const flagKey = configCase(stringName);
|
|
354
|
-
if (typeof flags[flagKey] !== 'string') {
|
|
355
|
-
flags[flagKey] = null;
|
|
586
|
+
else if (cmdArg === `--no-${dashCaseName}` || cmdArg === `--no${dashToPascalCase(dashCaseName)}`) {
|
|
587
|
+
value = false;
|
|
356
588
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
knownArgs.push(cmdArg);
|
|
364
|
-
}
|
|
365
|
-
else if (cmdArg === `--${stringName}`) {
|
|
366
|
-
flags[flagKey] = args[i + 1];
|
|
367
|
-
knownArgs.push(cmdArg);
|
|
368
|
-
knownArgs.push(args[i + 1]);
|
|
369
|
-
}
|
|
370
|
-
else if (cmdArg === `--${flagKey}`) {
|
|
371
|
-
flags[flagKey] = args[i + 1];
|
|
372
|
-
knownArgs.push(cmdArg);
|
|
373
|
-
knownArgs.push(args[i + 1]);
|
|
374
|
-
}
|
|
375
|
-
else if (cmdArg.startsWith(`--${flagKey}=`)) {
|
|
376
|
-
const values = cmdArg.split('=');
|
|
377
|
-
values.shift();
|
|
378
|
-
flags[flagKey] = values.join('=');
|
|
379
|
-
knownArgs.push(cmdArg);
|
|
380
|
-
}
|
|
381
|
-
else if (alias) {
|
|
382
|
-
if (cmdArg.startsWith(`-${alias}=`)) {
|
|
383
|
-
const values = cmdArg.split('=');
|
|
384
|
-
values.shift();
|
|
385
|
-
flags[flagKey] = values.join('=');
|
|
386
|
-
knownArgs.push(cmdArg);
|
|
387
|
-
}
|
|
388
|
-
else if (cmdArg === `-${alias}`) {
|
|
389
|
-
flags[flagKey] = args[i + 1];
|
|
390
|
-
knownArgs.push(args[i + 1]);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
589
|
+
else if (alias && cmdArg === `-${alias}`) {
|
|
590
|
+
value = true;
|
|
591
|
+
}
|
|
592
|
+
if (value !== undefined && cmdArg !== undefined) {
|
|
593
|
+
flags[configCaseName] = value;
|
|
594
|
+
flags.knownArgs.push(cmdArg);
|
|
393
595
|
}
|
|
394
596
|
});
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* Parse a string CLI argument
|
|
600
|
+
*
|
|
601
|
+
* @param flags the config flags object, while we'll modify
|
|
602
|
+
* @param args our CLI arguments
|
|
603
|
+
* @param configCaseName the argument we want to look at right now
|
|
604
|
+
*/
|
|
605
|
+
const parseStringArg = (flags, args, configCaseName) => {
|
|
606
|
+
if (typeof flags[configCaseName] !== 'string') {
|
|
607
|
+
flags[configCaseName] = null;
|
|
608
|
+
}
|
|
609
|
+
const { value, matchingArg } = getValue(args, configCaseName);
|
|
610
|
+
if (value !== undefined && matchingArg !== undefined) {
|
|
611
|
+
flags[configCaseName] = value;
|
|
612
|
+
flags.knownArgs.push(matchingArg);
|
|
613
|
+
flags.knownArgs.push(value);
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
/**
|
|
617
|
+
* Parse a number CLI argument
|
|
618
|
+
*
|
|
619
|
+
* @param flags the config flags object, while we'll modify
|
|
620
|
+
* @param args our CLI arguments
|
|
621
|
+
* @param configCaseName the argument we want to look at right now
|
|
622
|
+
*/
|
|
623
|
+
const parseNumberArg = (flags, args, configCaseName) => {
|
|
624
|
+
if (typeof flags[configCaseName] !== 'number') {
|
|
625
|
+
flags[configCaseName] = null;
|
|
626
|
+
}
|
|
627
|
+
const { value, matchingArg } = getValue(args, configCaseName);
|
|
628
|
+
if (value !== undefined && matchingArg !== undefined) {
|
|
629
|
+
flags[configCaseName] = parseInt(value, 10);
|
|
630
|
+
flags.knownArgs.push(matchingArg);
|
|
631
|
+
flags.knownArgs.push(value);
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
/**
|
|
635
|
+
* Parse a CLI argument which may be either a string or a number
|
|
636
|
+
*
|
|
637
|
+
* @param flags the config flags object, while we'll modify
|
|
638
|
+
* @param args our CLI arguments
|
|
639
|
+
* @param configCaseName the argument we want to look at right now
|
|
640
|
+
*/
|
|
641
|
+
const parseStringNumberArg = (flags, args, configCaseName) => {
|
|
642
|
+
if (!['number', 'string'].includes(typeof flags[configCaseName])) {
|
|
643
|
+
flags[configCaseName] = null;
|
|
644
|
+
}
|
|
645
|
+
const { value, matchingArg } = getValue(args, configCaseName);
|
|
646
|
+
if (value !== undefined && matchingArg !== undefined) {
|
|
647
|
+
if (CLI_ARG_STRING_REGEX.test(value)) {
|
|
648
|
+
// if it matches the regex we treat it like a string
|
|
649
|
+
flags[configCaseName] = value;
|
|
400
650
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
651
|
+
else {
|
|
652
|
+
// it was a number, great!
|
|
653
|
+
flags[configCaseName] = Number(value);
|
|
654
|
+
}
|
|
655
|
+
flags.knownArgs.push(matchingArg);
|
|
656
|
+
flags.knownArgs.push(value);
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
/**
|
|
660
|
+
* We use this regular expression to detect CLI parameters which
|
|
661
|
+
* should be parsed as string values (as opposed to numbers) for
|
|
662
|
+
* the argument types for which we support both a string and a
|
|
663
|
+
* number value.
|
|
664
|
+
*
|
|
665
|
+
* The regex tests for the presence of at least one character which is
|
|
666
|
+
* _not_ a digit (`\d`), a period (`\.`), or one of the characters `"e"`,
|
|
667
|
+
* `"E"`, `"+"`, or `"-"` (the latter four characters are necessary to
|
|
668
|
+
* support the admittedly unlikely use of scientific notation, like `"4e+0"`
|
|
669
|
+
* for `4`).
|
|
670
|
+
*
|
|
671
|
+
* Thus we'll match a string like `"50%"`, but not a string like `"50"` or
|
|
672
|
+
* `"5.0"`. If it matches a given string we conclude that the string should
|
|
673
|
+
* be parsed as a string literal, rather than using `Number` to convert it
|
|
674
|
+
* to a number.
|
|
675
|
+
*/
|
|
676
|
+
const CLI_ARG_STRING_REGEX = /[^\d\.Ee\+\-]+/g;
|
|
677
|
+
/**
|
|
678
|
+
* Parse a LogLevel CLI argument. These can be only a specific
|
|
679
|
+
* set of strings, so this function takes care of validating that
|
|
680
|
+
* the value is correct.
|
|
681
|
+
*
|
|
682
|
+
* @param flags the config flags object, while we'll modify
|
|
683
|
+
* @param args our CLI arguments
|
|
684
|
+
* @param configCaseName the argument we want to look at right now
|
|
685
|
+
*/
|
|
686
|
+
const parseLogLevelArg = (flags, args, configCaseName) => {
|
|
687
|
+
if (typeof flags[configCaseName] !== 'string') {
|
|
688
|
+
flags[configCaseName] = null;
|
|
689
|
+
}
|
|
690
|
+
const { value, matchingArg } = getValue(args, configCaseName);
|
|
691
|
+
if (value !== undefined && matchingArg !== undefined && isLogLevel(value)) {
|
|
692
|
+
flags[configCaseName] = value;
|
|
693
|
+
flags.knownArgs.push(matchingArg);
|
|
694
|
+
flags.knownArgs.push(value);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* Helper for pulling values out from the raw array of CLI arguments. This logic
|
|
699
|
+
* is shared between a few different types of CLI args.
|
|
700
|
+
*
|
|
701
|
+
* We look for arguments in the following formats:
|
|
702
|
+
*
|
|
703
|
+
* - `--my-cli-argument value`
|
|
704
|
+
* - `--my-cli-argument=value`
|
|
705
|
+
* - `--myCliArgument value`
|
|
706
|
+
* - `--myCliArgument=value`
|
|
707
|
+
*
|
|
708
|
+
* We also check for shortened aliases, which we define for a few arguments.
|
|
709
|
+
*
|
|
710
|
+
* @param args the CLI args we're dealing with
|
|
711
|
+
* @param configCaseName the ConfigFlag key which we're looking to pull out a value for
|
|
712
|
+
* @returns the value for the flag as well as the exact string which it matched from
|
|
713
|
+
* the user input.
|
|
714
|
+
*/
|
|
715
|
+
const getValue = (args, configCaseName) => {
|
|
716
|
+
// for some CLI args we have a short alias, like 'c' for 'config'
|
|
717
|
+
const alias = CLI_ARG_ALIASES[configCaseName];
|
|
718
|
+
// we support supplying arguments in both dash-case and configCase
|
|
719
|
+
// for ease of use
|
|
720
|
+
const dashCaseName = toDashCase(configCaseName);
|
|
721
|
+
let value;
|
|
722
|
+
let matchingArg;
|
|
723
|
+
args.forEach((arg, i) => {
|
|
724
|
+
if (arg.startsWith(`--${dashCaseName}=`) || arg.startsWith(`--${configCaseName}=`)) {
|
|
725
|
+
value = getEqualsValue(arg);
|
|
726
|
+
matchingArg = arg;
|
|
727
|
+
}
|
|
728
|
+
else if (arg === `--${dashCaseName}` || arg === `--${configCaseName}`) {
|
|
729
|
+
value = args[i + 1];
|
|
730
|
+
matchingArg = arg;
|
|
731
|
+
}
|
|
732
|
+
else if (alias) {
|
|
733
|
+
if (arg.startsWith(`-${alias}=`)) {
|
|
734
|
+
value = getEqualsValue(arg);
|
|
735
|
+
matchingArg = arg;
|
|
422
736
|
}
|
|
423
|
-
else if (alias) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
values.shift();
|
|
427
|
-
flags[flagKey] = parseInt(values.join(''), 10);
|
|
428
|
-
knownArgs.push(cmdArg);
|
|
429
|
-
}
|
|
430
|
-
else if (cmdArg === `-${alias}`) {
|
|
431
|
-
flags[flagKey] = parseInt(args[i + 1], 10);
|
|
432
|
-
knownArgs.push(args[i + 1]);
|
|
433
|
-
}
|
|
737
|
+
else if (arg === `-${alias}`) {
|
|
738
|
+
value = args[i + 1];
|
|
739
|
+
matchingArg = arg;
|
|
434
740
|
}
|
|
435
741
|
}
|
|
436
742
|
});
|
|
743
|
+
return { value, matchingArg };
|
|
437
744
|
};
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
'prerender-external',
|
|
461
|
-
'prod',
|
|
462
|
-
'profile',
|
|
463
|
-
'service-worker',
|
|
464
|
-
'screenshot',
|
|
465
|
-
'serve',
|
|
466
|
-
'skip-node-check',
|
|
467
|
-
'spec',
|
|
468
|
-
'ssr',
|
|
469
|
-
'stats',
|
|
470
|
-
'update-screenshot',
|
|
471
|
-
'verbose',
|
|
472
|
-
'version',
|
|
473
|
-
'watch',
|
|
474
|
-
];
|
|
475
|
-
const NUMBER_ARG_OPTS = ['max-workers', 'port'];
|
|
476
|
-
const STRING_ARG_OPTS = [
|
|
477
|
-
'address',
|
|
478
|
-
'config',
|
|
479
|
-
'docs-json',
|
|
480
|
-
'emulate',
|
|
481
|
-
'log-level',
|
|
482
|
-
'root',
|
|
483
|
-
'screenshot-connector',
|
|
484
|
-
];
|
|
485
|
-
const ARG_OPTS_ALIASES = {
|
|
486
|
-
config: 'c',
|
|
487
|
-
help: 'h',
|
|
488
|
-
port: 'p',
|
|
489
|
-
version: 'v',
|
|
490
|
-
};
|
|
745
|
+
/**
|
|
746
|
+
* When a parameter is set in the format `--foobar=12` at the CLI (as opposed to
|
|
747
|
+
* `--foobar 12`) we want to get the value after the `=` sign
|
|
748
|
+
*
|
|
749
|
+
* @param commandArgument the arg in question
|
|
750
|
+
* @returns the value after the `=`
|
|
751
|
+
*/
|
|
752
|
+
const getEqualsValue = (commandArgument) => commandArgument.split('=').slice(1).join('=');
|
|
753
|
+
/**
|
|
754
|
+
* Small helper for getting type-system-level assurance that a `string` can be
|
|
755
|
+
* narrowed to a `LogLevel`
|
|
756
|
+
*
|
|
757
|
+
* @param maybeLogLevel the string to check
|
|
758
|
+
* @returns whether this is a `LogLevel`
|
|
759
|
+
*/
|
|
760
|
+
const isLogLevel = (maybeLogLevel) =>
|
|
761
|
+
// unfortunately `includes` is typed on `ReadonlyArray<T>` as `(el: T):
|
|
762
|
+
// boolean` so a `string` cannot be passed to `includes` on a
|
|
763
|
+
// `ReadonlyArray` 😢 thus we `as any`
|
|
764
|
+
//
|
|
765
|
+
// see microsoft/TypeScript#31018 for some discussion of this
|
|
766
|
+
LOG_LEVELS.includes(maybeLogLevel);
|
|
491
767
|
const getNpmConfigEnvArgs = (sys) => {
|
|
492
768
|
// process.env.npm_config_argv
|
|
493
769
|
// {"remain":["4444"],"cooked":["run","serve","--port","4444"],"original":["run","serve","--port","4444"]}
|
|
@@ -508,7 +784,7 @@ const getNpmConfigEnvArgs = (sys) => {
|
|
|
508
784
|
const dependencies = [
|
|
509
785
|
{
|
|
510
786
|
name: "@rindo/core",
|
|
511
|
-
version: "2.
|
|
787
|
+
version: "2.17.1",
|
|
512
788
|
main: "compiler/rindo.js",
|
|
513
789
|
resources: [
|
|
514
790
|
"package.json",
|
|
@@ -833,12 +1109,11 @@ const tryFn = async (fn, ...args) => {
|
|
|
833
1109
|
}
|
|
834
1110
|
return null;
|
|
835
1111
|
};
|
|
836
|
-
const isInteractive = (sys,
|
|
837
|
-
var _a;
|
|
1112
|
+
const isInteractive = (sys, flags, object) => {
|
|
838
1113
|
const terminalInfo = object ||
|
|
839
1114
|
Object.freeze({
|
|
840
1115
|
tty: sys.isTTY() ? true : false,
|
|
841
|
-
ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!
|
|
1116
|
+
ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!flags.ci,
|
|
842
1117
|
});
|
|
843
1118
|
return terminalInfo.tty && !terminalInfo.ci;
|
|
844
1119
|
};
|
|
@@ -862,19 +1137,19 @@ async function readJson(sys, path) {
|
|
|
862
1137
|
}
|
|
863
1138
|
/**
|
|
864
1139
|
* Does the command have the debug flag?
|
|
865
|
-
* @param
|
|
1140
|
+
* @param flags The configuration flags passed into the Rindo command
|
|
866
1141
|
* @returns true if --debug has been passed, otherwise false
|
|
867
1142
|
*/
|
|
868
|
-
function hasDebug(
|
|
869
|
-
return
|
|
1143
|
+
function hasDebug(flags) {
|
|
1144
|
+
return flags.debug;
|
|
870
1145
|
}
|
|
871
1146
|
/**
|
|
872
1147
|
* Does the command have the verbose and debug flags?
|
|
873
|
-
* @param
|
|
1148
|
+
* @param flags The configuration flags passed into the Rindo command
|
|
874
1149
|
* @returns true if both --debug and --verbose have been passed, otherwise false
|
|
875
1150
|
*/
|
|
876
|
-
function hasVerbose(
|
|
877
|
-
return
|
|
1151
|
+
function hasVerbose(flags) {
|
|
1152
|
+
return flags.verbose && hasDebug(flags);
|
|
878
1153
|
}
|
|
879
1154
|
|
|
880
1155
|
/**
|
|
@@ -885,7 +1160,7 @@ function hasVerbose(config) {
|
|
|
885
1160
|
* @returns true if telemetry should be sent, false otherwise
|
|
886
1161
|
*/
|
|
887
1162
|
async function shouldTrack(config, sys, ci) {
|
|
888
|
-
return !ci && isInteractive(sys, config) && (await checkTelemetry(sys));
|
|
1163
|
+
return !ci && isInteractive(sys, config.flags) && (await checkTelemetry(sys));
|
|
889
1164
|
}
|
|
890
1165
|
|
|
891
1166
|
const isTest$1 = () => process.env.JEST_WORKER_ID !== undefined;
|
|
@@ -942,7 +1217,9 @@ async function updateConfig(sys, newOptions) {
|
|
|
942
1217
|
return await writeConfig(sys, Object.assign(config, newOptions));
|
|
943
1218
|
}
|
|
944
1219
|
|
|
1220
|
+
const isOutputTargetHydrate = (o) => o.type === DIST_HYDRATE_SCRIPT;
|
|
945
1221
|
const isOutputTargetDocs = (o) => o.type === DOCS_README || o.type === DOCS_JSON || o.type === DOCS_CUSTOM || o.type === DOCS_VSCODE;
|
|
1222
|
+
const DIST_HYDRATE_SCRIPT = 'dist-hydrate-script';
|
|
946
1223
|
const DOCS_CUSTOM = 'docs-custom';
|
|
947
1224
|
const DOCS_JSON = 'docs-json';
|
|
948
1225
|
const DOCS_README = 'docs-readme';
|
|
@@ -954,11 +1231,10 @@ const WWW = 'www';
|
|
|
954
1231
|
*
|
|
955
1232
|
* @param sys The system where the command is invoked
|
|
956
1233
|
* @param config The config passed into the Rindo command
|
|
957
|
-
* @param logger The tool used to do logging
|
|
958
1234
|
* @param coreCompiler The compiler used to do builds
|
|
959
1235
|
* @param result The results of a compiler build.
|
|
960
1236
|
*/
|
|
961
|
-
async function telemetryBuildFinishedAction(sys, config,
|
|
1237
|
+
async function telemetryBuildFinishedAction(sys, config, coreCompiler, result) {
|
|
962
1238
|
const tracking = await shouldTrack(config, sys, config.flags.ci);
|
|
963
1239
|
if (!tracking) {
|
|
964
1240
|
return;
|
|
@@ -966,20 +1242,19 @@ async function telemetryBuildFinishedAction(sys, config, logger, coreCompiler, r
|
|
|
966
1242
|
const component_count = Object.keys(result.componentGraph).length;
|
|
967
1243
|
const data = await prepareData(coreCompiler, config, sys, result.duration, component_count);
|
|
968
1244
|
await sendMetric(sys, config, 'rindo_cli_command', data);
|
|
969
|
-
logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
|
|
1245
|
+
config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
|
|
970
1246
|
}
|
|
971
1247
|
/**
|
|
972
1248
|
* A function to wrap a compiler task function around. Will send telemetry if, and only if, the machine allows.
|
|
1249
|
+
*
|
|
973
1250
|
* @param sys The system where the command is invoked
|
|
974
1251
|
* @param config The config passed into the Rindo command
|
|
975
|
-
* @param logger The tool used to do logging
|
|
976
1252
|
* @param coreCompiler The compiler used to do builds
|
|
977
1253
|
* @param action A Promise-based function to call in order to get the duration of any given command.
|
|
978
1254
|
* @returns void
|
|
979
1255
|
*/
|
|
980
|
-
async function telemetryAction(sys, config,
|
|
981
|
-
|
|
982
|
-
const tracking = await shouldTrack(config, sys, !!((_a = config === null || config === void 0 ? void 0 : config.flags) === null || _a === void 0 ? void 0 : _a.ci));
|
|
1256
|
+
async function telemetryAction(sys, config, coreCompiler, action) {
|
|
1257
|
+
const tracking = await shouldTrack(config, sys, !!config.flags.ci);
|
|
983
1258
|
let duration = undefined;
|
|
984
1259
|
let error;
|
|
985
1260
|
if (action) {
|
|
@@ -999,7 +1274,7 @@ async function telemetryAction(sys, config, logger, coreCompiler, action) {
|
|
|
999
1274
|
}
|
|
1000
1275
|
const data = await prepareData(coreCompiler, config, sys, duration);
|
|
1001
1276
|
await sendMetric(sys, config, 'rindo_cli_command', data);
|
|
1002
|
-
logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
|
|
1277
|
+
config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
|
|
1003
1278
|
if (error) {
|
|
1004
1279
|
throw error;
|
|
1005
1280
|
}
|
|
@@ -1015,6 +1290,16 @@ async function getActiveTargets(config) {
|
|
|
1015
1290
|
const result = config.outputTargets.map((t) => t.type);
|
|
1016
1291
|
return Array.from(new Set(result));
|
|
1017
1292
|
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Prepare data for telemetry
|
|
1295
|
+
*
|
|
1296
|
+
* @param coreCompiler the core compiler
|
|
1297
|
+
* @param config the current Rindo config
|
|
1298
|
+
* @param sys the compiler system instance in use
|
|
1299
|
+
* @param duration_ms the duration of the action being tracked
|
|
1300
|
+
* @param component_count the number of components being built (optional)
|
|
1301
|
+
* @returns a Promise wrapping data for the telemetry endpoint
|
|
1302
|
+
*/
|
|
1018
1303
|
const prepareData = async (coreCompiler, config, sys, duration_ms, component_count = undefined) => {
|
|
1019
1304
|
const { typescript, rollup } = coreCompiler.versions || { typescript: 'unknown', rollup: 'unknown' };
|
|
1020
1305
|
const { packages, packagesNoVersions } = await getInstalledPackages(sys, config);
|
|
@@ -1027,6 +1312,7 @@ const prepareData = async (coreCompiler, config, sys, duration_ms, component_cou
|
|
|
1027
1312
|
const cpu_model = sys.details.cpuModel;
|
|
1028
1313
|
const build = coreCompiler.buildId || 'unknown';
|
|
1029
1314
|
const has_app_pwa_config = hasAppTarget(config);
|
|
1315
|
+
const anonymizedConfig = anonymizeConfigForTelemetry(config);
|
|
1030
1316
|
return {
|
|
1031
1317
|
yarn,
|
|
1032
1318
|
duration_ms,
|
|
@@ -1046,12 +1332,83 @@ const prepareData = async (coreCompiler, config, sys, duration_ms, component_cou
|
|
|
1046
1332
|
typescript,
|
|
1047
1333
|
rollup,
|
|
1048
1334
|
has_app_pwa_config,
|
|
1335
|
+
config: anonymizedConfig,
|
|
1049
1336
|
};
|
|
1050
1337
|
};
|
|
1338
|
+
// props in output targets for which we retain their original values when
|
|
1339
|
+
// preparing a config for telemetry
|
|
1340
|
+
//
|
|
1341
|
+
// we omit the values of all other fields on output targets.
|
|
1342
|
+
const OUTPUT_TARGET_KEYS_TO_KEEP = ['type'];
|
|
1343
|
+
// top-level config props that we anonymize for telemetry
|
|
1344
|
+
const CONFIG_PROPS_TO_ANONYMIZE = [
|
|
1345
|
+
'rootDir',
|
|
1346
|
+
'fsNamespace',
|
|
1347
|
+
'packageJsonFilePath',
|
|
1348
|
+
'namespace',
|
|
1349
|
+
'srcDir',
|
|
1350
|
+
'srcIndexHtml',
|
|
1351
|
+
'buildLogFilePath',
|
|
1352
|
+
'cacheDir',
|
|
1353
|
+
'configPath',
|
|
1354
|
+
'tsconfig',
|
|
1355
|
+
];
|
|
1356
|
+
// Props we delete entirely from the config for telemetry
|
|
1357
|
+
//
|
|
1358
|
+
// TODO: Investigate improving anonymization for tsCompilerOptions and devServer
|
|
1359
|
+
const CONFIG_PROPS_TO_DELETE = ['sys', 'logger', 'tsCompilerOptions', 'devServer'];
|
|
1360
|
+
/**
|
|
1361
|
+
* Anonymize the config for telemetry, replacing potentially revealing config props
|
|
1362
|
+
* with a placeholder string if they are present (this lets us still track how frequently
|
|
1363
|
+
* these config options are being used)
|
|
1364
|
+
*
|
|
1365
|
+
* @param config the config to anonymize
|
|
1366
|
+
* @returns an anonymized copy of the same config
|
|
1367
|
+
*/
|
|
1368
|
+
const anonymizeConfigForTelemetry = (config) => {
|
|
1369
|
+
var _a;
|
|
1370
|
+
const anonymizedConfig = { ...config };
|
|
1371
|
+
for (const prop of CONFIG_PROPS_TO_ANONYMIZE) {
|
|
1372
|
+
if (anonymizedConfig[prop] !== undefined) {
|
|
1373
|
+
anonymizedConfig[prop] = 'omitted';
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
anonymizedConfig.outputTargets = ((_a = config.outputTargets) !== null && _a !== void 0 ? _a : []).map((target) => {
|
|
1377
|
+
// Anonymize the outputTargets on our configuration, taking advantage of the
|
|
1378
|
+
// optional 2nd argument to `JSON.stringify`. If anything is not a string
|
|
1379
|
+
// we retain it so that any nested properties are handled, else we check
|
|
1380
|
+
// whether it's in our 'keep' list to decide whether to keep it or replace it
|
|
1381
|
+
// with `"omitted"`.
|
|
1382
|
+
const anonymizedOT = JSON.parse(JSON.stringify(target, (key, value) => {
|
|
1383
|
+
if (!(typeof value === 'string')) {
|
|
1384
|
+
return value;
|
|
1385
|
+
}
|
|
1386
|
+
if (OUTPUT_TARGET_KEYS_TO_KEEP.includes(key)) {
|
|
1387
|
+
return value;
|
|
1388
|
+
}
|
|
1389
|
+
return 'omitted';
|
|
1390
|
+
}));
|
|
1391
|
+
// this prop has to be handled separately because it is an array
|
|
1392
|
+
// so the replace function above will be called with all of its
|
|
1393
|
+
// members, giving us `["omitted", "omitted", ...]`.
|
|
1394
|
+
//
|
|
1395
|
+
// Instead, we check for its presence and manually copy over.
|
|
1396
|
+
if (isOutputTargetHydrate(target) && target.external) {
|
|
1397
|
+
anonymizedOT['external'] = target.external.concat();
|
|
1398
|
+
}
|
|
1399
|
+
return anonymizedOT;
|
|
1400
|
+
});
|
|
1401
|
+
// TODO: Investigate improving anonymization for tsCompilerOptions and devServer
|
|
1402
|
+
for (const prop of CONFIG_PROPS_TO_DELETE) {
|
|
1403
|
+
delete anonymizedConfig[prop];
|
|
1404
|
+
}
|
|
1405
|
+
return anonymizedConfig;
|
|
1406
|
+
};
|
|
1051
1407
|
/**
|
|
1052
1408
|
* Reads package-lock.json, yarn.lock, and package.json files in order to cross-reference
|
|
1053
1409
|
* the dependencies and devDependencies properties. Pulls up the current installed version
|
|
1054
1410
|
* of each package under the @rindo, @navify, and @jigra scopes.
|
|
1411
|
+
*
|
|
1055
1412
|
* @param sys the system instance where telemetry is invoked
|
|
1056
1413
|
* @param config the Rindo configuration associated with the current task that triggered telemetry
|
|
1057
1414
|
* @returns an object listing all dev and production dependencies under the aforementioned scopes
|
|
@@ -1085,7 +1442,7 @@ async function getInstalledPackages(sys, config) {
|
|
|
1085
1442
|
return { packages, packagesNoVersions };
|
|
1086
1443
|
}
|
|
1087
1444
|
catch (err) {
|
|
1088
|
-
hasDebug(config) && console.error(err);
|
|
1445
|
+
hasDebug(config.flags) && console.error(err);
|
|
1089
1446
|
return { packages, packagesNoVersions };
|
|
1090
1447
|
}
|
|
1091
1448
|
}
|
|
@@ -1134,6 +1491,7 @@ function sanitizeDeclaredVersion(version) {
|
|
|
1134
1491
|
}
|
|
1135
1492
|
/**
|
|
1136
1493
|
* If telemetry is enabled, send a metric to an external data store
|
|
1494
|
+
*
|
|
1137
1495
|
* @param sys the system instance where telemetry is invoked
|
|
1138
1496
|
* @param config the Rindo configuration associated with the current task that triggered telemetry
|
|
1139
1497
|
* @param name the name of a trackable metric. Note this name is not necessarily a scalar value to track, like
|
|
@@ -1149,10 +1507,11 @@ async function sendMetric(sys, config, name, value) {
|
|
|
1149
1507
|
value,
|
|
1150
1508
|
session_id,
|
|
1151
1509
|
};
|
|
1152
|
-
await sendTelemetry(sys, config,
|
|
1510
|
+
await sendTelemetry(sys, config, message);
|
|
1153
1511
|
}
|
|
1154
1512
|
/**
|
|
1155
1513
|
* Used to read the config file's tokens.telemetry property.
|
|
1514
|
+
*
|
|
1156
1515
|
* @param sys The system where the command is invoked
|
|
1157
1516
|
* @returns string
|
|
1158
1517
|
*/
|
|
@@ -1174,7 +1533,7 @@ async function sendTelemetry(sys, config, data) {
|
|
|
1174
1533
|
try {
|
|
1175
1534
|
const now = new Date().toISOString();
|
|
1176
1535
|
const body = {
|
|
1177
|
-
metrics: [data
|
|
1536
|
+
metrics: [data],
|
|
1178
1537
|
sent_at: now,
|
|
1179
1538
|
};
|
|
1180
1539
|
// This request is only made if telemetry is on.
|
|
@@ -1185,15 +1544,15 @@ async function sendTelemetry(sys, config, data) {
|
|
|
1185
1544
|
},
|
|
1186
1545
|
body: JSON.stringify(body),
|
|
1187
1546
|
});
|
|
1188
|
-
hasVerbose(config) &&
|
|
1189
|
-
console.debug('\nSent %O metric to events service (status: %O)', data.
|
|
1547
|
+
hasVerbose(config.flags) &&
|
|
1548
|
+
console.debug('\nSent %O metric to events service (status: %O)', data.name, response.status, '\n');
|
|
1190
1549
|
if (response.status !== 204) {
|
|
1191
|
-
hasVerbose(config) &&
|
|
1550
|
+
hasVerbose(config.flags) &&
|
|
1192
1551
|
console.debug('\nBad response from events service. Request body: %O', response.body.toString(), '\n');
|
|
1193
1552
|
}
|
|
1194
1553
|
}
|
|
1195
1554
|
catch (e) {
|
|
1196
|
-
hasVerbose(config) && console.debug('Telemetry request failed:', e);
|
|
1555
|
+
hasVerbose(config.flags) && console.debug('Telemetry request failed:', e);
|
|
1197
1556
|
}
|
|
1198
1557
|
}
|
|
1199
1558
|
/**
|
|
@@ -1250,7 +1609,7 @@ const taskBuild = async (coreCompiler, config, sys) => {
|
|
|
1250
1609
|
const results = await compiler.build();
|
|
1251
1610
|
// TODO: make this parameter no longer optional, remove the surrounding if statement
|
|
1252
1611
|
if (sys) {
|
|
1253
|
-
await telemetryBuildFinishedAction(sys, config,
|
|
1612
|
+
await telemetryBuildFinishedAction(sys, config, coreCompiler, results);
|
|
1254
1613
|
}
|
|
1255
1614
|
await compiler.destroy();
|
|
1256
1615
|
if (results.hasError) {
|
|
@@ -1288,7 +1647,8 @@ const IS_NODE_ENV = typeof global !== 'undefined' &&
|
|
|
1288
1647
|
typeof require === 'function' &&
|
|
1289
1648
|
!!global.process &&
|
|
1290
1649
|
typeof __filename === 'string' &&
|
|
1291
|
-
(!global.origin || typeof global.origin !== 'string');
|
|
1650
|
+
(!global.origin || typeof global.origin !== 'string');
|
|
1651
|
+
const IS_BROWSER_ENV = typeof location !== 'undefined' && typeof navigator !== 'undefined' && typeof XMLHttpRequest !== 'undefined';
|
|
1292
1652
|
|
|
1293
1653
|
/**
|
|
1294
1654
|
* Task to generate component boilerplate and write it to disk. This task can
|
|
@@ -1337,7 +1697,8 @@ const taskGenerate = async (coreCompiler, config) => {
|
|
|
1337
1697
|
if (!writtenFiles) {
|
|
1338
1698
|
return config.sys.exit(1);
|
|
1339
1699
|
}
|
|
1340
|
-
//
|
|
1700
|
+
// We use `console.log` here rather than our `config.logger` because we don't want
|
|
1701
|
+
// our TUI messages to be prefixed with timestamps and so on.
|
|
1341
1702
|
console.log();
|
|
1342
1703
|
console.log(`${config.logger.gray('$')} rindo generate ${input}`);
|
|
1343
1704
|
console.log();
|
|
@@ -1481,7 +1842,8 @@ export class ${toPascalCase(tagName)} {
|
|
|
1481
1842
|
`;
|
|
1482
1843
|
};
|
|
1483
1844
|
/**
|
|
1484
|
-
* Get the boilerplate for style
|
|
1845
|
+
* Get the boilerplate for style for a generated component
|
|
1846
|
+
* @returns a boilerplate CSS block
|
|
1485
1847
|
*/
|
|
1486
1848
|
const getStyleUrlBoilerplate = () => `:host {
|
|
1487
1849
|
display: block;
|
|
@@ -1535,10 +1897,17 @@ describe('${tagName}', () => {
|
|
|
1535
1897
|
*/
|
|
1536
1898
|
const toPascalCase = (str) => str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');
|
|
1537
1899
|
|
|
1538
|
-
|
|
1900
|
+
/**
|
|
1901
|
+
* Entrypoint for the Telemetry task
|
|
1902
|
+
* @param flags configuration flags provided to Rindo when a task was called (either this task or a task that invokes
|
|
1903
|
+
* telemetry)
|
|
1904
|
+
* @param sys the abstraction for interfacing with the operating system
|
|
1905
|
+
* @param logger a logging implementation to log the results out to the user
|
|
1906
|
+
*/
|
|
1907
|
+
const taskTelemetry = async (flags, sys, logger) => {
|
|
1539
1908
|
const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
|
|
1540
|
-
const isEnabling =
|
|
1541
|
-
const isDisabling =
|
|
1909
|
+
const isEnabling = flags.args.includes('on');
|
|
1910
|
+
const isDisabling = flags.args.includes('off');
|
|
1542
1911
|
const INFORMATION = `Opt in or our of telemetry. Information about the data we collect is available on our website: ${logger.bold('https://rindojs.web.app/telemetry')}`;
|
|
1543
1912
|
const THANK_YOU = `Thank you for helping to make Rindo better! 💖`;
|
|
1544
1913
|
const ENABLED_MESSAGE = `${logger.green('Enabled')}. ${THANK_YOU}\n\n`;
|
|
@@ -1567,7 +1936,14 @@ const taskTelemetry = async (config, sys, logger) => {
|
|
|
1567
1936
|
`);
|
|
1568
1937
|
};
|
|
1569
1938
|
|
|
1570
|
-
|
|
1939
|
+
/**
|
|
1940
|
+
* Entrypoint for the Help task, providing Rindo usage context to the user
|
|
1941
|
+
* @param flags configuration flags provided to Rindo when a task was call (either this task or a task that invokes
|
|
1942
|
+
* telemetry)
|
|
1943
|
+
* @param logger a logging implementation to log the results out to the user
|
|
1944
|
+
* @param sys the abstraction for interfacing with the operating system
|
|
1945
|
+
*/
|
|
1946
|
+
const taskHelp = async (flags, logger, sys) => {
|
|
1571
1947
|
const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
|
|
1572
1948
|
console.log(`
|
|
1573
1949
|
${logger.bold('Build:')} ${logger.dim('Build components for development or production.')}
|
|
@@ -1600,7 +1976,7 @@ const taskHelp = async (config, logger, sys) => {
|
|
|
1600
1976
|
`);
|
|
1601
1977
|
// TODO: make this parameter no longer optional, remove the surrounding if statement
|
|
1602
1978
|
if (sys) {
|
|
1603
|
-
await taskTelemetry(
|
|
1979
|
+
await taskTelemetry(flags, sys, logger);
|
|
1604
1980
|
}
|
|
1605
1981
|
console.log(`
|
|
1606
1982
|
${logger.bold('Examples:')}
|
|
@@ -1657,6 +2033,95 @@ const taskServe = async (config) => {
|
|
|
1657
2033
|
});
|
|
1658
2034
|
};
|
|
1659
2035
|
|
|
2036
|
+
/**
|
|
2037
|
+
* Creates an instance of a logger
|
|
2038
|
+
* @returns the new logger instance
|
|
2039
|
+
*/
|
|
2040
|
+
const createLogger = () => {
|
|
2041
|
+
let useColors = IS_BROWSER_ENV;
|
|
2042
|
+
let level = 'info';
|
|
2043
|
+
return {
|
|
2044
|
+
enableColors: (uc) => (useColors = uc),
|
|
2045
|
+
getLevel: () => level,
|
|
2046
|
+
setLevel: (l) => (level = l),
|
|
2047
|
+
emoji: (e) => e,
|
|
2048
|
+
info: console.log.bind(console),
|
|
2049
|
+
warn: console.warn.bind(console),
|
|
2050
|
+
error: console.error.bind(console),
|
|
2051
|
+
debug: console.debug.bind(console),
|
|
2052
|
+
red: (msg) => msg,
|
|
2053
|
+
green: (msg) => msg,
|
|
2054
|
+
yellow: (msg) => msg,
|
|
2055
|
+
blue: (msg) => msg,
|
|
2056
|
+
magenta: (msg) => msg,
|
|
2057
|
+
cyan: (msg) => msg,
|
|
2058
|
+
gray: (msg) => msg,
|
|
2059
|
+
bold: (msg) => msg,
|
|
2060
|
+
dim: (msg) => msg,
|
|
2061
|
+
bgRed: (msg) => msg,
|
|
2062
|
+
createTimeSpan: (_startMsg, _debug = false) => ({
|
|
2063
|
+
duration: () => 0,
|
|
2064
|
+
finish: () => 0,
|
|
2065
|
+
}),
|
|
2066
|
+
printDiagnostics(diagnostics) {
|
|
2067
|
+
diagnostics.forEach((diagnostic) => logDiagnostic(diagnostic, useColors));
|
|
2068
|
+
},
|
|
2069
|
+
};
|
|
2070
|
+
};
|
|
2071
|
+
const logDiagnostic = (diagnostic, useColors) => {
|
|
2072
|
+
let color = BLUE;
|
|
2073
|
+
let prefix = 'Build';
|
|
2074
|
+
let msg = '';
|
|
2075
|
+
if (diagnostic.level === 'error') {
|
|
2076
|
+
color = RED;
|
|
2077
|
+
prefix = 'Error';
|
|
2078
|
+
}
|
|
2079
|
+
else if (diagnostic.level === 'warn') {
|
|
2080
|
+
color = YELLOW;
|
|
2081
|
+
prefix = 'Warning';
|
|
2082
|
+
}
|
|
2083
|
+
if (diagnostic.header) {
|
|
2084
|
+
prefix = diagnostic.header;
|
|
2085
|
+
}
|
|
2086
|
+
const filePath = diagnostic.relFilePath || diagnostic.absFilePath;
|
|
2087
|
+
if (filePath) {
|
|
2088
|
+
msg += filePath;
|
|
2089
|
+
if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > 0) {
|
|
2090
|
+
msg += ', line ' + diagnostic.lineNumber;
|
|
2091
|
+
if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > 0) {
|
|
2092
|
+
msg += ', column ' + diagnostic.columnNumber;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
msg += '\n';
|
|
2096
|
+
}
|
|
2097
|
+
msg += diagnostic.messageText;
|
|
2098
|
+
if (diagnostic.lines && diagnostic.lines.length > 0) {
|
|
2099
|
+
diagnostic.lines.forEach((l) => {
|
|
2100
|
+
msg += '\n' + l.lineNumber + ': ' + l.text;
|
|
2101
|
+
});
|
|
2102
|
+
msg += '\n';
|
|
2103
|
+
}
|
|
2104
|
+
if (useColors) {
|
|
2105
|
+
const styledPrefix = [
|
|
2106
|
+
'%c' + prefix,
|
|
2107
|
+
`background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`,
|
|
2108
|
+
];
|
|
2109
|
+
console.log(...styledPrefix, msg);
|
|
2110
|
+
}
|
|
2111
|
+
else if (diagnostic.level === 'error') {
|
|
2112
|
+
console.error(msg);
|
|
2113
|
+
}
|
|
2114
|
+
else if (diagnostic.level === 'warn') {
|
|
2115
|
+
console.warn(msg);
|
|
2116
|
+
}
|
|
2117
|
+
else {
|
|
2118
|
+
console.log(msg);
|
|
2119
|
+
}
|
|
2120
|
+
};
|
|
2121
|
+
const YELLOW = `#f39c12`;
|
|
2122
|
+
const RED = `#c0392b`;
|
|
2123
|
+
const BLUE = `#3498db`;
|
|
2124
|
+
|
|
1660
2125
|
const run = async (init) => {
|
|
1661
2126
|
const { args, logger, sys } = init;
|
|
1662
2127
|
try {
|
|
@@ -1672,7 +2137,7 @@ const run = async (init) => {
|
|
|
1672
2137
|
sys.applyGlobalPatch(sys.getCurrentDirectory());
|
|
1673
2138
|
}
|
|
1674
2139
|
if (task === 'help' || flags.help) {
|
|
1675
|
-
await taskHelp({
|
|
2140
|
+
await taskHelp({ task: 'help', args }, logger, sys);
|
|
1676
2141
|
return;
|
|
1677
2142
|
}
|
|
1678
2143
|
startupLog(logger, task);
|
|
@@ -1698,7 +2163,7 @@ const run = async (init) => {
|
|
|
1698
2163
|
startupLogVersion(logger, task, coreCompiler);
|
|
1699
2164
|
loadedCompilerLog(sys, logger, flags, coreCompiler);
|
|
1700
2165
|
if (task === 'info') {
|
|
1701
|
-
await telemetryAction(sys, { flags: { task: 'info' },
|
|
2166
|
+
await telemetryAction(sys, { flags: { task: 'info' }, logger }, coreCompiler, async () => {
|
|
1702
2167
|
await taskInfo(coreCompiler, sys, logger);
|
|
1703
2168
|
});
|
|
1704
2169
|
return;
|
|
@@ -1721,7 +2186,7 @@ const run = async (init) => {
|
|
|
1721
2186
|
sys.applyGlobalPatch(validated.config.rootDir);
|
|
1722
2187
|
}
|
|
1723
2188
|
await sys.ensureResources({ rootDir: validated.config.rootDir, logger, dependencies: dependencies });
|
|
1724
|
-
await telemetryAction(sys, validated.config,
|
|
2189
|
+
await telemetryAction(sys, validated.config, coreCompiler, async () => {
|
|
1725
2190
|
await runTask(coreCompiler, validated.config, task, sys);
|
|
1726
2191
|
});
|
|
1727
2192
|
}
|
|
@@ -1734,40 +2199,42 @@ const run = async (init) => {
|
|
|
1734
2199
|
}
|
|
1735
2200
|
};
|
|
1736
2201
|
const runTask = async (coreCompiler, config, task, sys) => {
|
|
1737
|
-
|
|
1738
|
-
|
|
2202
|
+
var _a, _b;
|
|
2203
|
+
const logger = (_a = config.logger) !== null && _a !== void 0 ? _a : createLogger();
|
|
2204
|
+
const strictConfig = { ...config, flags: (_b = { ...config.flags }) !== null && _b !== void 0 ? _b : { task }, logger };
|
|
2205
|
+
strictConfig.outputTargets = strictConfig.outputTargets || [];
|
|
1739
2206
|
switch (task) {
|
|
1740
2207
|
case 'build':
|
|
1741
|
-
await taskBuild(coreCompiler,
|
|
2208
|
+
await taskBuild(coreCompiler, strictConfig, sys);
|
|
1742
2209
|
break;
|
|
1743
2210
|
case 'docs':
|
|
1744
|
-
await taskDocs(coreCompiler,
|
|
2211
|
+
await taskDocs(coreCompiler, strictConfig);
|
|
1745
2212
|
break;
|
|
1746
2213
|
case 'generate':
|
|
1747
2214
|
case 'g':
|
|
1748
|
-
await taskGenerate(coreCompiler,
|
|
2215
|
+
await taskGenerate(coreCompiler, strictConfig);
|
|
1749
2216
|
break;
|
|
1750
2217
|
case 'help':
|
|
1751
|
-
await taskHelp(
|
|
2218
|
+
await taskHelp(strictConfig.flags, strictConfig.logger, sys);
|
|
1752
2219
|
break;
|
|
1753
2220
|
case 'prerender':
|
|
1754
|
-
await taskPrerender(coreCompiler,
|
|
2221
|
+
await taskPrerender(coreCompiler, strictConfig);
|
|
1755
2222
|
break;
|
|
1756
2223
|
case 'serve':
|
|
1757
|
-
await taskServe(
|
|
2224
|
+
await taskServe(strictConfig);
|
|
1758
2225
|
break;
|
|
1759
2226
|
case 'telemetry':
|
|
1760
2227
|
// TODO: make this parameter no longer optional, remove the surrounding if statement
|
|
1761
2228
|
if (sys) {
|
|
1762
|
-
await taskTelemetry(
|
|
2229
|
+
await taskTelemetry(strictConfig.flags, sys, strictConfig.logger);
|
|
1763
2230
|
}
|
|
1764
2231
|
break;
|
|
1765
2232
|
case 'version':
|
|
1766
2233
|
console.log(coreCompiler.version);
|
|
1767
2234
|
break;
|
|
1768
2235
|
default:
|
|
1769
|
-
|
|
1770
|
-
await taskHelp(
|
|
2236
|
+
strictConfig.logger.error(`${strictConfig.logger.emoji('❌ ')}Invalid rindo command, please see the options below:`);
|
|
2237
|
+
await taskHelp(strictConfig.flags, strictConfig.logger, sys);
|
|
1771
2238
|
return config.sys.exit(1);
|
|
1772
2239
|
}
|
|
1773
2240
|
};
|