@stencil/core 2.17.0 → 2.17.2

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 (50) hide show
  1. package/cli/config-flags.d.ts +110 -0
  2. package/cli/index.cjs +675 -253
  3. package/cli/index.d.ts +3 -2
  4. package/cli/index.js +675 -253
  5. package/cli/package.json +1 -1
  6. package/compiler/package.json +1 -1
  7. package/compiler/stencil.js +676 -226
  8. package/compiler/stencil.min.js +2 -2
  9. package/dependencies.json +1 -1
  10. package/dev-server/client/index.js +1 -1
  11. package/dev-server/client/package.json +1 -1
  12. package/dev-server/connector.html +2 -2
  13. package/dev-server/index.js +1 -1
  14. package/dev-server/package.json +1 -1
  15. package/dev-server/server-process.js +2 -2
  16. package/internal/app-data/package.json +1 -1
  17. package/internal/client/css-shim.js +1 -1
  18. package/internal/client/dom.js +1 -1
  19. package/internal/client/index.js +11 -6
  20. package/internal/client/package.json +1 -1
  21. package/internal/client/patch-browser.js +1 -1
  22. package/internal/client/patch-esm.js +1 -1
  23. package/internal/client/shadow-css.js +1 -1
  24. package/internal/hydrate/index.js +2 -2
  25. package/internal/hydrate/package.json +1 -1
  26. package/internal/package.json +1 -1
  27. package/internal/stencil-private.d.ts +14 -4
  28. package/internal/stencil-public-compiler.d.ts +67 -48
  29. package/internal/testing/index.js +1 -1
  30. package/internal/testing/package.json +1 -1
  31. package/mock-doc/index.cjs +41 -3
  32. package/mock-doc/index.d.ts +15 -0
  33. package/mock-doc/index.js +41 -3
  34. package/mock-doc/package.json +1 -1
  35. package/package.json +2 -1
  36. package/screenshot/package.json +1 -1
  37. package/sys/node/index.js +4 -4
  38. package/sys/node/package.json +1 -1
  39. package/sys/node/worker.js +1 -1
  40. package/testing/index.d.ts +1 -1
  41. package/testing/index.js +71 -40
  42. package/testing/jest/jest-config.d.ts +1 -1
  43. package/testing/jest/jest-runner.d.ts +3 -2
  44. package/testing/jest/jest-screenshot.d.ts +1 -1
  45. package/testing/mocks.d.ts +28 -2
  46. package/testing/package.json +1 -1
  47. package/testing/puppeteer/puppeteer-browser.d.ts +2 -2
  48. package/testing/test/testing-utils.spec.d.ts +1 -0
  49. package/testing/testing-utils.d.ts +74 -2
  50. package/testing/testing.d.ts +2 -2
package/cli/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Stencil CLI (CommonJS) v2.17.0 | MIT Licensed | https://stenciljs.com
2
+ Stencil CLI (CommonJS) v2.17.2 | MIT Licensed | https://stenciljs.com
3
3
  */
4
4
  'use strict';
5
5
 
@@ -25,8 +25,50 @@ function _interopNamespace(e) {
25
25
  return Object.freeze(n);
26
26
  }
27
27
 
28
- const toLowerCase = (str) => str.toLowerCase();
29
- const dashToPascalCase = (str) => toLowerCase(str)
28
+ /**
29
+ * This sets the log level hierarchy for our terminal logger, ranging from
30
+ * most to least verbose.
31
+ *
32
+ * Ordering the levels like this lets us easily check whether we should log a
33
+ * message at a given time. For instance, if the log level is set to `'warn'`,
34
+ * then anything passed to the logger with level `'warn'` or `'error'` should
35
+ * be logged, but we should _not_ log anything with level `'info'` or `'debug'`.
36
+ *
37
+ * If we have a current log level `currentLevel` and a message with level
38
+ * `msgLevel` is passed to the logger, we can determine whether or not we should
39
+ * log it by checking if the log level on the message is further up or at the
40
+ * same level in the hierarchy than `currentLevel`, like so:
41
+ *
42
+ * ```ts
43
+ * LOG_LEVELS.indexOf(msgLevel) >= LOG_LEVELS.indexOf(currentLevel)
44
+ * ```
45
+ *
46
+ * NOTE: for the reasons described above, do not change the order of the entries
47
+ * in this array without good reason!
48
+ */
49
+ const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
50
+
51
+ /**
52
+ * Convert a string from PascalCase to dash-case
53
+ *
54
+ * @param str the string to convert
55
+ * @returns a converted string
56
+ */
57
+ const toDashCase = (str) => str
58
+ .replace(/([A-Z0-9])/g, (match) => ` ${match[0]}`)
59
+ .trim()
60
+ .split(' ')
61
+ .join('-')
62
+ .toLowerCase();
63
+ /**
64
+ * Convert a string from dash-case / kebab-case to PascalCase (or CamelCase,
65
+ * or whatever you call it!)
66
+ *
67
+ * @param str a string to convert
68
+ * @returns a converted string
69
+ */
70
+ const dashToPascalCase = (str) => str
71
+ .toLowerCase()
30
72
  .split('-')
31
73
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
32
74
  .join('');
@@ -299,174 +341,13 @@ const validateComponentTag = (tag) => {
299
341
  return undefined;
300
342
  };
301
343
 
302
- const parseFlags = (args, sys) => {
303
- const flags = {
304
- task: null,
305
- args: [],
306
- knownArgs: [],
307
- unknownArgs: null,
308
- };
309
- // cmd line has more priority over npm scripts cmd
310
- flags.args = args.slice();
311
- if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
312
- flags.task = flags.args[0];
313
- }
314
- parseArgs(flags, flags.args, flags.knownArgs);
315
- if (sys && sys.name === 'node') {
316
- const envArgs = getNpmConfigEnvArgs(sys);
317
- parseArgs(flags, envArgs, flags.knownArgs);
318
- envArgs.forEach((envArg) => {
319
- if (!flags.args.includes(envArg)) {
320
- flags.args.push(envArg);
321
- }
322
- });
323
- }
324
- if (flags.task != null) {
325
- const i = flags.args.indexOf(flags.task);
326
- if (i > -1) {
327
- flags.args.splice(i, 1);
328
- }
329
- }
330
- flags.unknownArgs = flags.args.filter((arg) => {
331
- return !flags.knownArgs.includes(arg);
332
- });
333
- return flags;
334
- };
335
344
  /**
336
- * Parse command line arguments that are whitelisted via the BOOLEAN_ARG_OPTS,
337
- * STRING_ARG_OPTS, and NUMBER_ARG_OPTS arrays in this file. Handles leading
338
- * dashes on arguments, aliases that are defined for a small number of argument
339
- * types, and parsing values for non-boolean arguments (e.g. port number).
340
- *
341
- * @param flags a ConfigFlags object
342
- * @param args an array of command-line arguments to parse
343
- * @param knownArgs an array to which all recognized, legal arguments are added
344
- */
345
- const parseArgs = (flags, args, knownArgs) => {
346
- BOOLEAN_ARG_OPTS.forEach((booleanName) => {
347
- const alias = ARG_OPTS_ALIASES[booleanName];
348
- const flagKey = configCase(booleanName);
349
- if (typeof flags[flagKey] !== 'boolean') {
350
- flags[flagKey] = null;
351
- }
352
- args.forEach((cmdArg) => {
353
- if (cmdArg === `--${booleanName}`) {
354
- flags[flagKey] = true;
355
- knownArgs.push(cmdArg);
356
- }
357
- else if (cmdArg === `--${flagKey}`) {
358
- flags[flagKey] = true;
359
- knownArgs.push(cmdArg);
360
- }
361
- else if (cmdArg === `--no-${booleanName}`) {
362
- flags[flagKey] = false;
363
- knownArgs.push(cmdArg);
364
- }
365
- else if (cmdArg === `--no${dashToPascalCase(booleanName)}`) {
366
- flags[flagKey] = false;
367
- knownArgs.push(cmdArg);
368
- }
369
- else if (alias && cmdArg === `-${alias}`) {
370
- flags[flagKey] = true;
371
- knownArgs.push(cmdArg);
372
- }
373
- });
374
- });
375
- STRING_ARG_OPTS.forEach((stringName) => {
376
- const alias = ARG_OPTS_ALIASES[stringName];
377
- const flagKey = configCase(stringName);
378
- if (typeof flags[flagKey] !== 'string') {
379
- flags[flagKey] = null;
380
- }
381
- for (let i = 0; i < args.length; i++) {
382
- const cmdArg = args[i];
383
- if (cmdArg.startsWith(`--${stringName}=`)) {
384
- const values = cmdArg.split('=');
385
- values.shift();
386
- flags[flagKey] = values.join('=');
387
- knownArgs.push(cmdArg);
388
- }
389
- else if (cmdArg === `--${stringName}`) {
390
- flags[flagKey] = args[i + 1];
391
- knownArgs.push(cmdArg);
392
- knownArgs.push(args[i + 1]);
393
- }
394
- else if (cmdArg === `--${flagKey}`) {
395
- flags[flagKey] = args[i + 1];
396
- knownArgs.push(cmdArg);
397
- knownArgs.push(args[i + 1]);
398
- }
399
- else if (cmdArg.startsWith(`--${flagKey}=`)) {
400
- const values = cmdArg.split('=');
401
- values.shift();
402
- flags[flagKey] = values.join('=');
403
- knownArgs.push(cmdArg);
404
- }
405
- else if (alias) {
406
- if (cmdArg.startsWith(`-${alias}=`)) {
407
- const values = cmdArg.split('=');
408
- values.shift();
409
- flags[flagKey] = values.join('=');
410
- knownArgs.push(cmdArg);
411
- }
412
- else if (cmdArg === `-${alias}`) {
413
- flags[flagKey] = args[i + 1];
414
- knownArgs.push(args[i + 1]);
415
- }
416
- }
417
- }
418
- });
419
- NUMBER_ARG_OPTS.forEach((numberName) => {
420
- const alias = ARG_OPTS_ALIASES[numberName];
421
- const flagKey = configCase(numberName);
422
- if (typeof flags[flagKey] !== 'number') {
423
- flags[flagKey] = null;
424
- }
425
- for (let i = 0; i < args.length; i++) {
426
- const cmdArg = args[i];
427
- if (cmdArg.startsWith(`--${numberName}=`)) {
428
- const values = cmdArg.split('=');
429
- values.shift();
430
- flags[flagKey] = parseInt(values.join(''), 10);
431
- knownArgs.push(cmdArg);
432
- }
433
- else if (cmdArg === `--${numberName}`) {
434
- flags[flagKey] = parseInt(args[i + 1], 10);
435
- knownArgs.push(args[i + 1]);
436
- }
437
- else if (cmdArg.startsWith(`--${flagKey}=`)) {
438
- const values = cmdArg.split('=');
439
- values.shift();
440
- flags[flagKey] = parseInt(values.join(''), 10);
441
- knownArgs.push(cmdArg);
442
- }
443
- else if (cmdArg === `--${flagKey}`) {
444
- flags[flagKey] = parseInt(args[i + 1], 10);
445
- knownArgs.push(args[i + 1]);
446
- }
447
- else if (alias) {
448
- if (cmdArg.startsWith(`-${alias}=`)) {
449
- const values = cmdArg.split('=');
450
- values.shift();
451
- flags[flagKey] = parseInt(values.join(''), 10);
452
- knownArgs.push(cmdArg);
453
- }
454
- else if (cmdArg === `-${alias}`) {
455
- flags[flagKey] = parseInt(args[i + 1], 10);
456
- knownArgs.push(args[i + 1]);
457
- }
458
- }
459
- }
460
- });
461
- };
462
- const configCase = (prop) => {
463
- prop = dashToPascalCase(prop);
464
- return prop.charAt(0).toLowerCase() + prop.slice(1);
465
- };
466
- const BOOLEAN_ARG_OPTS = [
345
+ * All the Boolean options supported by the Stencil CLI
346
+ */
347
+ const BOOLEAN_CLI_ARGS = [
467
348
  'build',
468
349
  'cache',
469
- 'check-version',
350
+ 'checkVersion',
470
351
  'ci',
471
352
  'compare',
472
353
  'debug',
@@ -481,58 +362,474 @@ const BOOLEAN_ARG_OPTS = [
481
362
  'log',
482
363
  'open',
483
364
  'prerender',
484
- 'prerender-external',
365
+ 'prerenderExternal',
485
366
  'prod',
486
367
  'profile',
487
- 'service-worker',
368
+ 'serviceWorker',
488
369
  'screenshot',
489
370
  'serve',
490
- 'skip-node-check',
371
+ 'skipNodeCheck',
491
372
  'spec',
492
373
  'ssr',
493
374
  'stats',
494
- 'update-screenshot',
375
+ 'updateScreenshot',
495
376
  'verbose',
496
377
  'version',
497
378
  'watch',
379
+ // JEST CLI OPTIONS
380
+ 'all',
381
+ 'automock',
382
+ 'bail',
383
+ // 'cache', Stencil already supports this argument
384
+ 'changedFilesWithAncestor',
385
+ // 'ci', Stencil already supports this argument
386
+ 'clearCache',
387
+ 'clearMocks',
388
+ 'collectCoverage',
389
+ 'color',
390
+ 'colors',
391
+ 'coverage',
392
+ // 'debug', Stencil already supports this argument
393
+ 'detectLeaks',
394
+ 'detectOpenHandles',
395
+ 'errorOnDeprecated',
396
+ 'expand',
397
+ 'findRelatedTests',
398
+ 'forceExit',
399
+ 'init',
400
+ 'injectGlobals',
401
+ 'json',
402
+ 'lastCommit',
403
+ 'listTests',
404
+ 'logHeapUsage',
405
+ 'noStackTrace',
406
+ 'notify',
407
+ 'onlyChanged',
408
+ 'onlyFailures',
409
+ 'passWithNoTests',
410
+ 'resetMocks',
411
+ 'resetModules',
412
+ 'restoreMocks',
413
+ 'runInBand',
414
+ 'runTestsByPath',
415
+ 'showConfig',
416
+ 'silent',
417
+ 'skipFilter',
418
+ 'testLocationInResults',
419
+ 'updateSnapshot',
420
+ 'useStderr',
421
+ // 'verbose', Stencil already supports this argument
422
+ // 'version', Stencil already supports this argument
423
+ // 'watch', Stencil already supports this argument
424
+ 'watchAll',
425
+ 'watchman',
426
+ ];
427
+ /**
428
+ * All the Number options supported by the Stencil CLI
429
+ */
430
+ const NUMBER_CLI_ARGS = [
431
+ 'port',
432
+ // JEST CLI ARGS
433
+ 'maxConcurrency',
434
+ 'testTimeout',
498
435
  ];
499
- const NUMBER_ARG_OPTS = ['max-workers', 'port'];
500
- const STRING_ARG_OPTS = [
436
+ /**
437
+ * All the String options supported by the Stencil CLI
438
+ */
439
+ const STRING_CLI_ARGS = [
501
440
  'address',
502
441
  'config',
503
- 'docs-json',
442
+ 'docsApi',
443
+ 'docsJson',
504
444
  'emulate',
505
- 'log-level',
506
445
  'root',
507
- 'screenshot-connector',
446
+ 'screenshotConnector',
447
+ // JEST CLI ARGS
448
+ 'cacheDirectory',
449
+ 'changedSince',
450
+ 'collectCoverageFrom',
451
+ // 'config', Stencil already supports this argument
452
+ 'coverageDirectory',
453
+ 'coverageThreshold',
454
+ 'env',
455
+ 'filter',
456
+ 'globalSetup',
457
+ 'globalTeardown',
458
+ 'globals',
459
+ 'haste',
460
+ 'moduleNameMapper',
461
+ 'notifyMode',
462
+ 'outputFile',
463
+ 'preset',
464
+ 'prettierPath',
465
+ 'resolver',
466
+ 'rootDir',
467
+ 'runner',
468
+ 'testEnvironment',
469
+ 'testEnvironmentOptions',
470
+ 'testFailureExitCode',
471
+ 'testNamePattern',
472
+ 'testResultsProcessor',
473
+ 'testRunner',
474
+ 'testSequencer',
475
+ 'testURL',
476
+ 'timers',
477
+ 'transform',
478
+ // ARRAY ARGS
479
+ 'collectCoverageOnlyFrom',
480
+ 'coveragePathIgnorePatterns',
481
+ 'coverageReporters',
482
+ 'moduleDirectories',
483
+ 'moduleFileExtensions',
484
+ 'modulePathIgnorePatterns',
485
+ 'modulePaths',
486
+ 'projects',
487
+ 'reporters',
488
+ 'roots',
489
+ 'selectProjects',
490
+ 'setupFiles',
491
+ 'setupFilesAfterEnv',
492
+ 'snapshotSerializers',
493
+ 'testMatch',
494
+ 'testPathIgnorePatterns',
495
+ 'testPathPattern',
496
+ 'testRegex',
497
+ 'transformIgnorePatterns',
498
+ 'unmockedModulePathPatterns',
499
+ 'watchPathIgnorePatterns',
508
500
  ];
509
- const ARG_OPTS_ALIASES = {
501
+ /**
502
+ * All the CLI arguments which may have string or number values
503
+ *
504
+ * `maxWorkers` is an argument which is used both by Stencil _and_ by Jest,
505
+ * which means that we need to support parsing both string and number values.
506
+ */
507
+ const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
508
+ /**
509
+ * All the LogLevel-type options supported by the Stencil CLI
510
+ *
511
+ * This is a bit silly since there's only one such argument atm,
512
+ * but this approach lets us make sure that we're handling all
513
+ * our arguments in a type-safe way.
514
+ */
515
+ const LOG_LEVEL_CLI_ARGS = ['logLevel'];
516
+ /**
517
+ * For a small subset of CLI options we support a short alias e.g. `'h'` for `'help'`
518
+ */
519
+ const CLI_ARG_ALIASES = {
510
520
  config: 'c',
511
521
  help: 'h',
512
522
  port: 'p',
513
523
  version: 'v',
514
524
  };
515
- const getNpmConfigEnvArgs = (sys) => {
516
- // process.env.npm_config_argv
517
- // {"remain":["4444"],"cooked":["run","serve","--port","4444"],"original":["run","serve","--port","4444"]}
518
- let args = [];
519
- try {
520
- const npmConfigArgs = sys.getEnvironmentVar('npm_config_argv');
521
- if (npmConfigArgs) {
522
- args = JSON.parse(npmConfigArgs).original;
523
- if (args[0] === 'run') {
524
- args = args.slice(2);
525
- }
525
+ /**
526
+ * Helper function for initializing a `ConfigFlags` object. Provide any overrides
527
+ * for default values and off you go!
528
+ *
529
+ * @param init an object with any overrides for default values
530
+ * @returns a complete CLI flag object
531
+ */
532
+ const createConfigFlags = (init = {}) => {
533
+ const flags = {
534
+ task: null,
535
+ args: [],
536
+ knownArgs: [],
537
+ unknownArgs: [],
538
+ ...init,
539
+ };
540
+ return flags;
541
+ };
542
+
543
+ /**
544
+ * Parse command line arguments into a structured `ConfigFlags` object
545
+ *
546
+ * @param args an array of CLI flags
547
+ * @param _sys an optional compiler system
548
+ * @returns a structured ConfigFlags object
549
+ */
550
+ const parseFlags = (args, _sys) => {
551
+ // TODO(STENCIL-509): remove the _sys parameter here ^^ (for v3)
552
+ const flags = createConfigFlags();
553
+ // cmd line has more priority over npm scripts cmd
554
+ flags.args = Array.isArray(args) ? args.slice() : [];
555
+ if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
556
+ flags.task = flags.args[0];
557
+ }
558
+ parseArgs(flags, flags.args);
559
+ if (flags.task != null) {
560
+ const i = flags.args.indexOf(flags.task);
561
+ if (i > -1) {
562
+ flags.args.splice(i, 1);
526
563
  }
527
564
  }
528
- catch (e) { }
529
- return args;
565
+ // to find unknown / unrecognized arguments we filter `args`, including only
566
+ // arguments whose normalized form is not found in `knownArgs`. `knownArgs`
567
+ // is populated during the call to `parseArgs` above. For arguments like
568
+ // `--foobar` the string `"--foobar"` will be added, while for more
569
+ // complicated arguments like `--bizBoz=bop` or `--bizBoz bop` just the
570
+ // string `"--bizBoz"` will be added.
571
+ flags.unknownArgs = flags.args.filter((arg) => !flags.knownArgs.includes(parseEqualsArg(arg)[0]));
572
+ return flags;
530
573
  };
574
+ /**
575
+ * Parse command line arguments that are enumerated in the `config-flags`
576
+ * module. Handles leading dashes on arguments, aliases that are defined for a
577
+ * small number of arguments, and parsing values for non-boolean arguments
578
+ * (e.g. port number for the dev server).
579
+ *
580
+ * @param flags a ConfigFlags object to which parsed arguments will be added
581
+ * @param args an array of command-line arguments to parse
582
+ */
583
+ const parseArgs = (flags, args) => {
584
+ BOOLEAN_CLI_ARGS.forEach((argName) => parseBooleanArg(flags, args, argName));
585
+ STRING_CLI_ARGS.forEach((argName) => parseStringArg(flags, args, argName));
586
+ NUMBER_CLI_ARGS.forEach((argName) => parseNumberArg(flags, args, argName));
587
+ STRING_NUMBER_CLI_ARGS.forEach((argName) => parseStringNumberArg(flags, args, argName));
588
+ LOG_LEVEL_CLI_ARGS.forEach((argName) => parseLogLevelArg(flags, args, argName));
589
+ };
590
+ /**
591
+ * Parse a boolean CLI argument. For these, we support the following formats:
592
+ *
593
+ * - `--booleanArg`
594
+ * - `--boolean-arg`
595
+ * - `--noBooleanArg`
596
+ * - `--no-boolean-arg`
597
+ *
598
+ * The final two variants should be parsed to a value of `false` on the config
599
+ * object.
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 parseBooleanArg = (flags, args, configCaseName) => {
606
+ // we support both dash-case and PascalCase versions of the parameter
607
+ // argName is 'configCase' version which can be found in BOOLEAN_ARG_OPTS
608
+ const alias = CLI_ARG_ALIASES[configCaseName];
609
+ const dashCaseName = toDashCase(configCaseName);
610
+ if (typeof flags[configCaseName] !== 'boolean') {
611
+ flags[configCaseName] = null;
612
+ }
613
+ args.forEach((cmdArg) => {
614
+ let value;
615
+ if (cmdArg === `--${configCaseName}` || cmdArg === `--${dashCaseName}`) {
616
+ value = true;
617
+ }
618
+ else if (cmdArg === `--no-${dashCaseName}` || cmdArg === `--no${dashToPascalCase(dashCaseName)}`) {
619
+ value = false;
620
+ }
621
+ else if (alias && cmdArg === `-${alias}`) {
622
+ value = true;
623
+ }
624
+ if (value !== undefined && cmdArg !== undefined) {
625
+ flags[configCaseName] = value;
626
+ flags.knownArgs.push(cmdArg);
627
+ }
628
+ });
629
+ };
630
+ /**
631
+ * Parse a string CLI argument
632
+ *
633
+ * @param flags the config flags object, while we'll modify
634
+ * @param args our CLI arguments
635
+ * @param configCaseName the argument we want to look at right now
636
+ */
637
+ const parseStringArg = (flags, args, configCaseName) => {
638
+ if (typeof flags[configCaseName] !== 'string') {
639
+ flags[configCaseName] = null;
640
+ }
641
+ const { value, matchingArg } = getValue(args, configCaseName);
642
+ if (value !== undefined && matchingArg !== undefined) {
643
+ flags[configCaseName] = value;
644
+ flags.knownArgs.push(matchingArg);
645
+ flags.knownArgs.push(value);
646
+ }
647
+ };
648
+ /**
649
+ * Parse a number CLI argument
650
+ *
651
+ * @param flags the config flags object, while we'll modify
652
+ * @param args our CLI arguments
653
+ * @param configCaseName the argument we want to look at right now
654
+ */
655
+ const parseNumberArg = (flags, args, configCaseName) => {
656
+ if (typeof flags[configCaseName] !== 'number') {
657
+ flags[configCaseName] = null;
658
+ }
659
+ const { value, matchingArg } = getValue(args, configCaseName);
660
+ if (value !== undefined && matchingArg !== undefined) {
661
+ flags[configCaseName] = parseInt(value, 10);
662
+ flags.knownArgs.push(matchingArg);
663
+ flags.knownArgs.push(value);
664
+ }
665
+ };
666
+ /**
667
+ * Parse a CLI argument which may be either a string or a number
668
+ *
669
+ * @param flags the config flags object, while we'll modify
670
+ * @param args our CLI arguments
671
+ * @param configCaseName the argument we want to look at right now
672
+ */
673
+ const parseStringNumberArg = (flags, args, configCaseName) => {
674
+ if (!['number', 'string'].includes(typeof flags[configCaseName])) {
675
+ flags[configCaseName] = null;
676
+ }
677
+ const { value, matchingArg } = getValue(args, configCaseName);
678
+ if (value !== undefined && matchingArg !== undefined) {
679
+ if (CLI_ARG_STRING_REGEX.test(value)) {
680
+ // if it matches the regex we treat it like a string
681
+ flags[configCaseName] = value;
682
+ }
683
+ else {
684
+ // it was a number, great!
685
+ flags[configCaseName] = Number(value);
686
+ }
687
+ flags.knownArgs.push(matchingArg);
688
+ flags.knownArgs.push(value);
689
+ }
690
+ };
691
+ /**
692
+ * We use this regular expression to detect CLI parameters which
693
+ * should be parsed as string values (as opposed to numbers) for
694
+ * the argument types for which we support both a string and a
695
+ * number value.
696
+ *
697
+ * The regex tests for the presence of at least one character which is
698
+ * _not_ a digit (`\d`), a period (`\.`), or one of the characters `"e"`,
699
+ * `"E"`, `"+"`, or `"-"` (the latter four characters are necessary to
700
+ * support the admittedly unlikely use of scientific notation, like `"4e+0"`
701
+ * for `4`).
702
+ *
703
+ * Thus we'll match a string like `"50%"`, but not a string like `"50"` or
704
+ * `"5.0"`. If it matches a given string we conclude that the string should
705
+ * be parsed as a string literal, rather than using `Number` to convert it
706
+ * to a number.
707
+ */
708
+ const CLI_ARG_STRING_REGEX = /[^\d\.Ee\+\-]+/g;
709
+ /**
710
+ * Parse a LogLevel CLI argument. These can be only a specific
711
+ * set of strings, so this function takes care of validating that
712
+ * the value is correct.
713
+ *
714
+ * @param flags the config flags object, while we'll modify
715
+ * @param args our CLI arguments
716
+ * @param configCaseName the argument we want to look at right now
717
+ */
718
+ const parseLogLevelArg = (flags, args, configCaseName) => {
719
+ if (typeof flags[configCaseName] !== 'string') {
720
+ flags[configCaseName] = null;
721
+ }
722
+ const { value, matchingArg } = getValue(args, configCaseName);
723
+ if (value !== undefined && matchingArg !== undefined && isLogLevel(value)) {
724
+ flags[configCaseName] = value;
725
+ flags.knownArgs.push(matchingArg);
726
+ flags.knownArgs.push(value);
727
+ }
728
+ };
729
+ /**
730
+ * Helper for pulling values out from the raw array of CLI arguments. This logic
731
+ * is shared between a few different types of CLI args.
732
+ *
733
+ * We look for arguments in the following formats:
734
+ *
735
+ * - `--my-cli-argument value`
736
+ * - `--my-cli-argument=value`
737
+ * - `--myCliArgument value`
738
+ * - `--myCliArgument=value`
739
+ *
740
+ * We also check for shortened aliases, which we define for a few arguments.
741
+ *
742
+ * @param args the CLI args we're dealing with
743
+ * @param configCaseName the ConfigFlag key which we're looking to pull out a value for
744
+ * @returns the value for the flag as well as the exact string which it matched from
745
+ * the user input.
746
+ */
747
+ const getValue = (args, configCaseName) => {
748
+ // for some CLI args we have a short alias, like 'c' for 'config'
749
+ const alias = CLI_ARG_ALIASES[configCaseName];
750
+ // we support supplying arguments in both dash-case and configCase
751
+ // for ease of use
752
+ const dashCaseName = toDashCase(configCaseName);
753
+ let value;
754
+ let matchingArg;
755
+ args.forEach((arg, i) => {
756
+ if (arg.startsWith(`--${dashCaseName}=`) || arg.startsWith(`--${configCaseName}=`)) {
757
+ // our argument was passed at the command-line in the format --argName=arg-value
758
+ [matchingArg, value] = parseEqualsArg(arg);
759
+ }
760
+ else if (arg === `--${dashCaseName}` || arg === `--${configCaseName}`) {
761
+ // the next value in the array is assumed to be a value for this argument
762
+ value = args[i + 1];
763
+ matchingArg = arg;
764
+ }
765
+ else if (alias) {
766
+ if (arg.startsWith(`-${alias}=`)) {
767
+ [matchingArg, value] = parseEqualsArg(arg);
768
+ }
769
+ else if (arg === `-${alias}`) {
770
+ value = args[i + 1];
771
+ matchingArg = arg;
772
+ }
773
+ }
774
+ });
775
+ return { value, matchingArg };
776
+ };
777
+ /**
778
+ * Parse an 'equals' argument, which is a CLI argument-value pair in the
779
+ * format `--foobar=12` (as opposed to a space-separated format like
780
+ * `--foobar 12`).
781
+ *
782
+ * To parse this we split on the `=`, returning the first part as the argument
783
+ * name and the second part as the value. We join the value on `"="` in case
784
+ * there is another `"="` in the argument.
785
+ *
786
+ * This function is safe to call with any arg, and can therefore be used as
787
+ * an argument 'normalizer'. If CLI argument is not an 'equals' argument then
788
+ * the return value will be a tuple of the original argument and an empty
789
+ * string `""` for the value.
790
+ *
791
+ * In code terms, if you do:
792
+ *
793
+ * ```ts
794
+ * const [arg, value] = parseEqualsArg("--myArgument")
795
+ * ```
796
+ *
797
+ * Then `arg` will be `"--myArgument"` and `value` will be `""`, whereas if
798
+ * you do:
799
+ *
800
+ *
801
+ * ```ts
802
+ * const [arg, value] = parseEqualsArg("--myArgument=myValue")
803
+ * ```
804
+ *
805
+ * Then `arg` will be `"--myArgument"` and `value` will be `"myValue"`.
806
+ *
807
+ * @param arg the arg in question
808
+ * @returns a tuple containing the arg name and the value (if present)
809
+ */
810
+ const parseEqualsArg = (arg) => {
811
+ const [originalArg, ...value] = arg.split('=');
812
+ return [originalArg, value.join('=')];
813
+ };
814
+ /**
815
+ * Small helper for getting type-system-level assurance that a `string` can be
816
+ * narrowed to a `LogLevel`
817
+ *
818
+ * @param maybeLogLevel the string to check
819
+ * @returns whether this is a `LogLevel`
820
+ */
821
+ const isLogLevel = (maybeLogLevel) =>
822
+ // unfortunately `includes` is typed on `ReadonlyArray<T>` as `(el: T):
823
+ // boolean` so a `string` cannot be passed to `includes` on a
824
+ // `ReadonlyArray` 😢 thus we `as any`
825
+ //
826
+ // see microsoft/TypeScript#31018 for some discussion of this
827
+ LOG_LEVELS.includes(maybeLogLevel);
531
828
 
532
829
  const dependencies = [
533
830
  {
534
831
  name: "@stencil/core",
535
- version: "2.17.0",
832
+ version: "2.17.2",
536
833
  main: "compiler/stencil.js",
537
834
  resources: [
538
835
  "package.json",
@@ -857,12 +1154,11 @@ const tryFn = async (fn, ...args) => {
857
1154
  }
858
1155
  return null;
859
1156
  };
860
- const isInteractive = (sys, config, object) => {
861
- var _a;
1157
+ const isInteractive = (sys, flags, object) => {
862
1158
  const terminalInfo = object ||
863
1159
  Object.freeze({
864
1160
  tty: sys.isTTY() ? true : false,
865
- ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!((_a = config.flags) === null || _a === void 0 ? void 0 : _a.ci),
1161
+ ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!flags.ci,
866
1162
  });
867
1163
  return terminalInfo.tty && !terminalInfo.ci;
868
1164
  };
@@ -887,19 +1183,19 @@ async function readJson(sys, path) {
887
1183
  }
888
1184
  /**
889
1185
  * Does the command have the debug flag?
890
- * @param config The config passed into the Stencil command
1186
+ * @param flags The configuration flags passed into the Stencil command
891
1187
  * @returns true if --debug has been passed, otherwise false
892
1188
  */
893
- function hasDebug(config) {
894
- return config.flags.debug;
1189
+ function hasDebug(flags) {
1190
+ return flags.debug;
895
1191
  }
896
1192
  /**
897
1193
  * Does the command have the verbose and debug flags?
898
- * @param config The config passed into the Stencil command
1194
+ * @param flags The configuration flags passed into the Stencil command
899
1195
  * @returns true if both --debug and --verbose have been passed, otherwise false
900
1196
  */
901
- function hasVerbose(config) {
902
- return config.flags.verbose && hasDebug(config);
1197
+ function hasVerbose(flags) {
1198
+ return flags.verbose && hasDebug(flags);
903
1199
  }
904
1200
 
905
1201
  /**
@@ -910,7 +1206,7 @@ function hasVerbose(config) {
910
1206
  * @returns true if telemetry should be sent, false otherwise
911
1207
  */
912
1208
  async function shouldTrack(config, sys, ci) {
913
- return !ci && isInteractive(sys, config) && (await checkTelemetry(sys));
1209
+ return !ci && isInteractive(sys, config.flags) && (await checkTelemetry(sys));
914
1210
  }
915
1211
 
916
1212
  const isTest$1 = () => process.env.JEST_WORKER_ID !== undefined;
@@ -981,11 +1277,10 @@ const WWW = 'www';
981
1277
  *
982
1278
  * @param sys The system where the command is invoked
983
1279
  * @param config The config passed into the Stencil command
984
- * @param logger The tool used to do logging
985
1280
  * @param coreCompiler The compiler used to do builds
986
1281
  * @param result The results of a compiler build.
987
1282
  */
988
- async function telemetryBuildFinishedAction(sys, config, logger, coreCompiler, result) {
1283
+ async function telemetryBuildFinishedAction(sys, config, coreCompiler, result) {
989
1284
  const tracking = await shouldTrack(config, sys, config.flags.ci);
990
1285
  if (!tracking) {
991
1286
  return;
@@ -993,21 +1288,19 @@ async function telemetryBuildFinishedAction(sys, config, logger, coreCompiler, r
993
1288
  const component_count = Object.keys(result.componentGraph).length;
994
1289
  const data = await prepareData(coreCompiler, config, sys, result.duration, component_count);
995
1290
  await sendMetric(sys, config, 'stencil_cli_command', data);
996
- logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
1291
+ config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
997
1292
  }
998
1293
  /**
999
1294
  * A function to wrap a compiler task function around. Will send telemetry if, and only if, the machine allows.
1000
1295
  *
1001
1296
  * @param sys The system where the command is invoked
1002
1297
  * @param config The config passed into the Stencil command
1003
- * @param logger The tool used to do logging
1004
1298
  * @param coreCompiler The compiler used to do builds
1005
1299
  * @param action A Promise-based function to call in order to get the duration of any given command.
1006
1300
  * @returns void
1007
1301
  */
1008
- async function telemetryAction(sys, config, logger, coreCompiler, action) {
1009
- var _a;
1010
- const tracking = await shouldTrack(config, sys, !!((_a = config === null || config === void 0 ? void 0 : config.flags) === null || _a === void 0 ? void 0 : _a.ci));
1302
+ async function telemetryAction(sys, config, coreCompiler, action) {
1303
+ const tracking = await shouldTrack(config, sys, !!config.flags.ci);
1011
1304
  let duration = undefined;
1012
1305
  let error;
1013
1306
  if (action) {
@@ -1027,11 +1320,20 @@ async function telemetryAction(sys, config, logger, coreCompiler, action) {
1027
1320
  }
1028
1321
  const data = await prepareData(coreCompiler, config, sys, duration);
1029
1322
  await sendMetric(sys, config, 'stencil_cli_command', data);
1030
- logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
1323
+ config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
1031
1324
  if (error) {
1032
1325
  throw error;
1033
1326
  }
1034
1327
  }
1328
+ /**
1329
+ * Helper function to determine if a Stencil configuration builds an application.
1330
+ *
1331
+ * This function is a rough approximation whether an application is generated as a part of a Stencil build, based on
1332
+ * contents of the project's `stencil.config.ts` file.
1333
+ *
1334
+ * @param config the configuration used by the Stencil project
1335
+ * @returns true if we believe the project generates an application, false otherwise
1336
+ */
1035
1337
  function hasAppTarget(config) {
1036
1338
  return config.outputTargets.some((target) => target.type === WWW && (!!target.serviceWorker || (!!target.baseUrl && target.baseUrl !== '/')));
1037
1339
  }
@@ -1039,7 +1341,15 @@ function isUsingYarn(sys) {
1039
1341
  var _a;
1040
1342
  return ((_a = sys.getEnvironmentVar('npm_execpath')) === null || _a === void 0 ? void 0 : _a.includes('yarn')) || false;
1041
1343
  }
1042
- async function getActiveTargets(config) {
1344
+ /**
1345
+ * Build a list of the different types of output targets used in a Stencil configuration.
1346
+ *
1347
+ * Duplicate entries will not be returned from the list
1348
+ *
1349
+ * @param config the configuration used by the Stencil project
1350
+ * @returns a unique list of output target types found in the Stencil configuration
1351
+ */
1352
+ function getActiveTargets(config) {
1043
1353
  const result = config.outputTargets.map((t) => t.type);
1044
1354
  return Array.from(new Set(result));
1045
1355
  }
@@ -1056,7 +1366,7 @@ async function getActiveTargets(config) {
1056
1366
  const prepareData = async (coreCompiler, config, sys, duration_ms, component_count = undefined) => {
1057
1367
  const { typescript, rollup } = coreCompiler.versions || { typescript: 'unknown', rollup: 'unknown' };
1058
1368
  const { packages, packagesNoVersions } = await getInstalledPackages(sys, config);
1059
- const targets = await getActiveTargets(config);
1369
+ const targets = getActiveTargets(config);
1060
1370
  const yarn = isUsingYarn(sys);
1061
1371
  const stencil = coreCompiler.version || 'unknown';
1062
1372
  const system = `${sys.name} ${sys.version}`;
@@ -1119,14 +1429,13 @@ const CONFIG_PROPS_TO_DELETE = ['sys', 'logger', 'tsCompilerOptions', 'devServer
1119
1429
  * @returns an anonymized copy of the same config
1120
1430
  */
1121
1431
  const anonymizeConfigForTelemetry = (config) => {
1122
- var _a;
1123
1432
  const anonymizedConfig = { ...config };
1124
1433
  for (const prop of CONFIG_PROPS_TO_ANONYMIZE) {
1125
1434
  if (anonymizedConfig[prop] !== undefined) {
1126
1435
  anonymizedConfig[prop] = 'omitted';
1127
1436
  }
1128
1437
  }
1129
- anonymizedConfig.outputTargets = ((_a = config.outputTargets) !== null && _a !== void 0 ? _a : []).map((target) => {
1438
+ anonymizedConfig.outputTargets = config.outputTargets.map((target) => {
1130
1439
  // Anonymize the outputTargets on our configuration, taking advantage of the
1131
1440
  // optional 2nd argument to `JSON.stringify`. If anything is not a string
1132
1441
  // we retain it so that any nested properties are handled, else we check
@@ -1195,7 +1504,7 @@ async function getInstalledPackages(sys, config) {
1195
1504
  return { packages, packagesNoVersions };
1196
1505
  }
1197
1506
  catch (err) {
1198
- hasDebug(config) && console.error(err);
1507
+ hasDebug(config.flags) && console.error(err);
1199
1508
  return { packages, packagesNoVersions };
1200
1509
  }
1201
1510
  }
@@ -1297,15 +1606,15 @@ async function sendTelemetry(sys, config, data) {
1297
1606
  },
1298
1607
  body: JSON.stringify(body),
1299
1608
  });
1300
- hasVerbose(config) &&
1609
+ hasVerbose(config.flags) &&
1301
1610
  console.debug('\nSent %O metric to events service (status: %O)', data.name, response.status, '\n');
1302
1611
  if (response.status !== 204) {
1303
- hasVerbose(config) &&
1612
+ hasVerbose(config.flags) &&
1304
1613
  console.debug('\nBad response from events service. Request body: %O', response.body.toString(), '\n');
1305
1614
  }
1306
1615
  }
1307
1616
  catch (e) {
1308
- hasVerbose(config) && console.debug('Telemetry request failed:', e);
1617
+ hasVerbose(config.flags) && console.debug('Telemetry request failed:', e);
1309
1618
  }
1310
1619
  }
1311
1620
  /**
@@ -1347,7 +1656,7 @@ function getMajorVersion(version) {
1347
1656
  return parts[0];
1348
1657
  }
1349
1658
 
1350
- const taskBuild = async (coreCompiler, config, sys) => {
1659
+ const taskBuild = async (coreCompiler, config) => {
1351
1660
  if (config.flags.watch) {
1352
1661
  // watch build
1353
1662
  await taskWatch(coreCompiler, config);
@@ -1360,10 +1669,7 @@ const taskBuild = async (coreCompiler, config, sys) => {
1360
1669
  const versionChecker = startCheckVersion(config, coreCompiler.version);
1361
1670
  const compiler = await coreCompiler.createCompiler(config);
1362
1671
  const results = await compiler.build();
1363
- // TODO(STENCIL-148) make this parameter no longer optional, remove the surrounding if statement
1364
- if (sys) {
1365
- await telemetryBuildFinishedAction(sys, config, config.logger, coreCompiler, results);
1366
- }
1672
+ await telemetryBuildFinishedAction(config.sys, config, coreCompiler, results);
1367
1673
  await compiler.destroy();
1368
1674
  if (results.hasError) {
1369
1675
  exitCode = 1;
@@ -1401,6 +1707,7 @@ const IS_NODE_ENV = typeof global !== 'undefined' &&
1401
1707
  !!global.process &&
1402
1708
  typeof __filename === 'string' &&
1403
1709
  (!global.origin || typeof global.origin !== 'string');
1710
+ const IS_BROWSER_ENV = typeof location !== 'undefined' && typeof navigator !== 'undefined' && typeof XMLHttpRequest !== 'undefined';
1404
1711
 
1405
1712
  /**
1406
1713
  * Task to generate component boilerplate and write it to disk. This task can
@@ -1596,7 +1903,8 @@ export class ${toPascalCase(tagName)} {
1596
1903
  `;
1597
1904
  };
1598
1905
  /**
1599
- * Get the boilerplate for style.
1906
+ * Get the boilerplate for style for a generated component
1907
+ * @returns a boilerplate CSS block
1600
1908
  */
1601
1909
  const getStyleUrlBoilerplate = () => `:host {
1602
1910
  display: block;
@@ -1650,10 +1958,17 @@ describe('${tagName}', () => {
1650
1958
  */
1651
1959
  const toPascalCase = (str) => str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');
1652
1960
 
1653
- const taskTelemetry = async (config, sys, logger) => {
1961
+ /**
1962
+ * Entrypoint for the Telemetry task
1963
+ * @param flags configuration flags provided to Stencil when a task was called (either this task or a task that invokes
1964
+ * telemetry)
1965
+ * @param sys the abstraction for interfacing with the operating system
1966
+ * @param logger a logging implementation to log the results out to the user
1967
+ */
1968
+ const taskTelemetry = async (flags, sys, logger) => {
1654
1969
  const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
1655
- const isEnabling = config.flags.args.includes('on');
1656
- const isDisabling = config.flags.args.includes('off');
1970
+ const isEnabling = flags.args.includes('on');
1971
+ const isDisabling = flags.args.includes('off');
1657
1972
  const INFORMATION = `Opt in or our of telemetry. Information about the data we collect is available on our website: ${logger.bold('https://stenciljs.com/telemetry')}`;
1658
1973
  const THANK_YOU = `Thank you for helping to make Stencil better! 💖`;
1659
1974
  const ENABLED_MESSAGE = `${logger.green('Enabled')}. ${THANK_YOU}\n\n`;
@@ -1682,7 +1997,14 @@ const taskTelemetry = async (config, sys, logger) => {
1682
1997
  `);
1683
1998
  };
1684
1999
 
1685
- const taskHelp = async (config, logger, sys) => {
2000
+ /**
2001
+ * Entrypoint for the Help task, providing Stencil usage context to the user
2002
+ * @param flags configuration flags provided to Stencil when a task was call (either this task or a task that invokes
2003
+ * telemetry)
2004
+ * @param logger a logging implementation to log the results out to the user
2005
+ * @param sys the abstraction for interfacing with the operating system
2006
+ */
2007
+ const taskHelp = async (flags, logger, sys) => {
1686
2008
  const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
1687
2009
  console.log(`
1688
2010
  ${logger.bold('Build:')} ${logger.dim('Build components for development or production.')}
@@ -1713,10 +2035,7 @@ const taskHelp = async (config, logger, sys) => {
1713
2035
  ${prompt} ${logger.green('stencil generate')} or ${logger.green('stencil g')}
1714
2036
 
1715
2037
  `);
1716
- // TODO(STENCIL-148) make this parameter no longer optional, remove the surrounding if statement
1717
- if (sys) {
1718
- await taskTelemetry(config, sys, logger);
1719
- }
2038
+ await taskTelemetry(flags, sys, logger);
1720
2039
  console.log(`
1721
2040
  ${logger.bold('Examples:')}
1722
2041
 
@@ -1772,6 +2091,10 @@ const taskServe = async (config) => {
1772
2091
  });
1773
2092
  };
1774
2093
 
2094
+ /**
2095
+ * Entrypoint for any Stencil tests
2096
+ * @param config a validated Stencil configuration entity
2097
+ */
1775
2098
  const taskTest = async (config) => {
1776
2099
  if (!IS_NODE_ENV) {
1777
2100
  config.logger.error(`"test" command is currently only implemented for a NodeJS environment`);
@@ -1818,10 +2141,99 @@ const taskTest = async (config) => {
1818
2141
  }
1819
2142
  };
1820
2143
 
2144
+ /**
2145
+ * Creates an instance of a logger
2146
+ * @returns the new logger instance
2147
+ */
2148
+ const createLogger = () => {
2149
+ let useColors = IS_BROWSER_ENV;
2150
+ let level = 'info';
2151
+ return {
2152
+ enableColors: (uc) => (useColors = uc),
2153
+ getLevel: () => level,
2154
+ setLevel: (l) => (level = l),
2155
+ emoji: (e) => e,
2156
+ info: console.log.bind(console),
2157
+ warn: console.warn.bind(console),
2158
+ error: console.error.bind(console),
2159
+ debug: console.debug.bind(console),
2160
+ red: (msg) => msg,
2161
+ green: (msg) => msg,
2162
+ yellow: (msg) => msg,
2163
+ blue: (msg) => msg,
2164
+ magenta: (msg) => msg,
2165
+ cyan: (msg) => msg,
2166
+ gray: (msg) => msg,
2167
+ bold: (msg) => msg,
2168
+ dim: (msg) => msg,
2169
+ bgRed: (msg) => msg,
2170
+ createTimeSpan: (_startMsg, _debug = false) => ({
2171
+ duration: () => 0,
2172
+ finish: () => 0,
2173
+ }),
2174
+ printDiagnostics(diagnostics) {
2175
+ diagnostics.forEach((diagnostic) => logDiagnostic(diagnostic, useColors));
2176
+ },
2177
+ };
2178
+ };
2179
+ const logDiagnostic = (diagnostic, useColors) => {
2180
+ let color = BLUE;
2181
+ let prefix = 'Build';
2182
+ let msg = '';
2183
+ if (diagnostic.level === 'error') {
2184
+ color = RED;
2185
+ prefix = 'Error';
2186
+ }
2187
+ else if (diagnostic.level === 'warn') {
2188
+ color = YELLOW;
2189
+ prefix = 'Warning';
2190
+ }
2191
+ if (diagnostic.header) {
2192
+ prefix = diagnostic.header;
2193
+ }
2194
+ const filePath = diagnostic.relFilePath || diagnostic.absFilePath;
2195
+ if (filePath) {
2196
+ msg += filePath;
2197
+ if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > 0) {
2198
+ msg += ', line ' + diagnostic.lineNumber;
2199
+ if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > 0) {
2200
+ msg += ', column ' + diagnostic.columnNumber;
2201
+ }
2202
+ }
2203
+ msg += '\n';
2204
+ }
2205
+ msg += diagnostic.messageText;
2206
+ if (diagnostic.lines && diagnostic.lines.length > 0) {
2207
+ diagnostic.lines.forEach((l) => {
2208
+ msg += '\n' + l.lineNumber + ': ' + l.text;
2209
+ });
2210
+ msg += '\n';
2211
+ }
2212
+ if (useColors) {
2213
+ const styledPrefix = [
2214
+ '%c' + prefix,
2215
+ `background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`,
2216
+ ];
2217
+ console.log(...styledPrefix, msg);
2218
+ }
2219
+ else if (diagnostic.level === 'error') {
2220
+ console.error(msg);
2221
+ }
2222
+ else if (diagnostic.level === 'warn') {
2223
+ console.warn(msg);
2224
+ }
2225
+ else {
2226
+ console.log(msg);
2227
+ }
2228
+ };
2229
+ const YELLOW = `#f39c12`;
2230
+ const RED = `#c0392b`;
2231
+ const BLUE = `#3498db`;
2232
+
1821
2233
  const run = async (init) => {
1822
2234
  const { args, logger, sys } = init;
1823
2235
  try {
1824
- const flags = parseFlags(args, sys);
2236
+ const flags = parseFlags(args);
1825
2237
  const task = flags.task;
1826
2238
  if (flags.debug || flags.verbose) {
1827
2239
  logger.setLevel('debug');
@@ -1833,7 +2245,7 @@ const run = async (init) => {
1833
2245
  sys.applyGlobalPatch(sys.getCurrentDirectory());
1834
2246
  }
1835
2247
  if (task === 'help' || flags.help) {
1836
- await taskHelp({ flags: { task: 'help', args }, outputTargets: [] }, logger, sys);
2248
+ await taskHelp(createConfigFlags({ task: 'help', args }), logger, sys);
1837
2249
  return;
1838
2250
  }
1839
2251
  startupLog(logger, task);
@@ -1859,9 +2271,7 @@ const run = async (init) => {
1859
2271
  startupLogVersion(logger, task, coreCompiler);
1860
2272
  loadedCompilerLog(sys, logger, flags, coreCompiler);
1861
2273
  if (task === 'info') {
1862
- await telemetryAction(sys, { flags: { task: 'info' }, outputTargets: [] }, logger, coreCompiler, async () => {
1863
- await taskInfo(coreCompiler, sys, logger);
1864
- });
2274
+ taskInfo(coreCompiler, sys, logger);
1865
2275
  return;
1866
2276
  }
1867
2277
  const validated = await coreCompiler.loadConfig({
@@ -1882,7 +2292,7 @@ const run = async (init) => {
1882
2292
  sys.applyGlobalPatch(validated.config.rootDir);
1883
2293
  }
1884
2294
  await sys.ensureResources({ rootDir: validated.config.rootDir, logger, dependencies: dependencies });
1885
- await telemetryAction(sys, validated.config, logger, coreCompiler, async () => {
2295
+ await telemetryAction(sys, validated.config, coreCompiler, async () => {
1886
2296
  await runTask(coreCompiler, validated.config, task, sys);
1887
2297
  });
1888
2298
  }
@@ -1894,44 +2304,56 @@ const run = async (init) => {
1894
2304
  }
1895
2305
  }
1896
2306
  };
2307
+ /**
2308
+ * Run a specified task
2309
+ * @param coreCompiler an instance of a minimal, bootstrap compiler for running the specified task
2310
+ * @param config a configuration for the Stencil project to apply to the task run
2311
+ * @param task the task to run
2312
+ * @param sys the {@link CompilerSystem} for interacting with the operating system
2313
+ * @public
2314
+ */
1897
2315
  const runTask = async (coreCompiler, config, task, sys) => {
1898
- config.flags = config.flags || { task };
1899
- config.outputTargets = config.outputTargets || [];
2316
+ var _a, _b, _c;
2317
+ const logger = (_a = config.logger) !== null && _a !== void 0 ? _a : createLogger();
2318
+ const strictConfig = {
2319
+ ...config,
2320
+ flags: createConfigFlags((_b = config.flags) !== null && _b !== void 0 ? _b : { task }),
2321
+ logger,
2322
+ outputTargets: (_c = config.outputTargets) !== null && _c !== void 0 ? _c : [],
2323
+ sys: sys !== null && sys !== void 0 ? sys : coreCompiler.createSystem({ logger }),
2324
+ };
1900
2325
  switch (task) {
1901
2326
  case 'build':
1902
- await taskBuild(coreCompiler, config, sys);
2327
+ await taskBuild(coreCompiler, strictConfig);
1903
2328
  break;
1904
2329
  case 'docs':
1905
- await taskDocs(coreCompiler, config);
2330
+ await taskDocs(coreCompiler, strictConfig);
1906
2331
  break;
1907
2332
  case 'generate':
1908
2333
  case 'g':
1909
- await taskGenerate(coreCompiler, config);
2334
+ await taskGenerate(coreCompiler, strictConfig);
1910
2335
  break;
1911
2336
  case 'help':
1912
- await taskHelp(config, config.logger, sys);
2337
+ await taskHelp(strictConfig.flags, strictConfig.logger, sys);
1913
2338
  break;
1914
2339
  case 'prerender':
1915
- await taskPrerender(coreCompiler, config);
2340
+ await taskPrerender(coreCompiler, strictConfig);
1916
2341
  break;
1917
2342
  case 'serve':
1918
- await taskServe(config);
2343
+ await taskServe(strictConfig);
1919
2344
  break;
1920
2345
  case 'telemetry':
1921
- // TODO(STENCIL-148) make this parameter no longer optional, remove the surrounding if statement
1922
- if (sys) {
1923
- await taskTelemetry(config, sys, config.logger);
1924
- }
2346
+ await taskTelemetry(strictConfig.flags, sys, strictConfig.logger);
1925
2347
  break;
1926
2348
  case 'test':
1927
- await taskTest(config);
2349
+ await taskTest(strictConfig);
1928
2350
  break;
1929
2351
  case 'version':
1930
2352
  console.log(coreCompiler.version);
1931
2353
  break;
1932
2354
  default:
1933
- config.logger.error(`${config.logger.emoji('❌ ')}Invalid stencil command, please see the options below:`);
1934
- await taskHelp(config, config.logger, sys);
2355
+ strictConfig.logger.error(`${strictConfig.logger.emoji('❌ ')}Invalid stencil command, please see the options below:`);
2356
+ await taskHelp(strictConfig.flags, strictConfig.logger, sys);
1935
2357
  return config.sys.exit(1);
1936
2358
  }
1937
2359
  };