@stencil/core 2.17.0 → 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.
Files changed (49) hide show
  1. package/cli/config-flags.d.ts +102 -0
  2. package/cli/index.cjs +603 -220
  3. package/cli/index.d.ts +2 -1
  4. package/cli/index.js +603 -220
  5. package/cli/package.json +1 -1
  6. package/compiler/package.json +1 -1
  7. package/compiler/stencil.js +337 -174
  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 +2 -2
  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 +1 -1
  32. package/mock-doc/index.js +1 -1
  33. package/mock-doc/package.json +1 -1
  34. package/package.json +2 -1
  35. package/screenshot/package.json +1 -1
  36. package/sys/node/index.js +4 -4
  37. package/sys/node/package.json +1 -1
  38. package/sys/node/worker.js +1 -1
  39. package/testing/index.d.ts +1 -1
  40. package/testing/index.js +40 -24
  41. package/testing/jest/jest-config.d.ts +1 -1
  42. package/testing/jest/jest-runner.d.ts +3 -2
  43. package/testing/jest/jest-screenshot.d.ts +1 -1
  44. package/testing/mocks.d.ts +27 -2
  45. package/testing/package.json +1 -1
  46. package/testing/puppeteer/puppeteer-browser.d.ts +2 -2
  47. package/testing/test/testing-utils.spec.d.ts +1 -0
  48. package/testing/testing-utils.d.ts +74 -2
  49. 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.1 | 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,22 +341,211 @@ const validateComponentTag = (tag) => {
299
341
  return undefined;
300
342
  };
301
343
 
344
+ /**
345
+ * All the Boolean options supported by the Stencil CLI
346
+ */
347
+ const BOOLEAN_CLI_ARGS = [
348
+ 'build',
349
+ 'cache',
350
+ 'checkVersion',
351
+ 'ci',
352
+ 'compare',
353
+ 'debug',
354
+ 'dev',
355
+ 'devtools',
356
+ 'docs',
357
+ 'e2e',
358
+ 'es5',
359
+ 'esm',
360
+ 'headless',
361
+ 'help',
362
+ 'log',
363
+ 'open',
364
+ 'prerender',
365
+ 'prerenderExternal',
366
+ 'prod',
367
+ 'profile',
368
+ 'serviceWorker',
369
+ 'screenshot',
370
+ 'serve',
371
+ 'skipNodeCheck',
372
+ 'spec',
373
+ 'ssr',
374
+ 'stats',
375
+ 'updateScreenshot',
376
+ 'verbose',
377
+ 'version',
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',
435
+ ];
436
+ /**
437
+ * All the String options supported by the Stencil CLI
438
+ */
439
+ const STRING_CLI_ARGS = [
440
+ 'address',
441
+ 'config',
442
+ 'docsApi',
443
+ 'docsJson',
444
+ 'emulate',
445
+ 'root',
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',
500
+ ];
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 = {
520
+ config: 'c',
521
+ help: 'h',
522
+ port: 'p',
523
+ version: 'v',
524
+ };
525
+
526
+ /**
527
+ * Parse command line arguments into a structured `ConfigFlags` object
528
+ *
529
+ * @param args an array of config flags
530
+ * @param sys an optional compiler system
531
+ * @returns a structured ConfigFlags object
532
+ */
302
533
  const parseFlags = (args, sys) => {
303
534
  const flags = {
304
535
  task: null,
305
536
  args: [],
306
537
  knownArgs: [],
307
- unknownArgs: null,
538
+ unknownArgs: [],
308
539
  };
309
540
  // cmd line has more priority over npm scripts cmd
310
- flags.args = args.slice();
541
+ flags.args = Array.isArray(args) ? args.slice() : [];
311
542
  if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
312
543
  flags.task = flags.args[0];
313
544
  }
314
- parseArgs(flags, flags.args, flags.knownArgs);
545
+ parseArgs(flags, flags.args);
315
546
  if (sys && sys.name === 'node') {
316
547
  const envArgs = getNpmConfigEnvArgs(sys);
317
- parseArgs(flags, envArgs, flags.knownArgs);
548
+ parseArgs(flags, envArgs);
318
549
  envArgs.forEach((envArg) => {
319
550
  if (!flags.args.includes(envArg)) {
320
551
  flags.args.push(envArg);
@@ -333,185 +564,230 @@ const parseFlags = (args, sys) => {
333
564
  return flags;
334
565
  };
335
566
  /**
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).
567
+ * Parse command line arguments that are enumerated in the `config-flags`
568
+ * module. Handles leading dashes on arguments, aliases that are defined for a
569
+ * small number of arguments, and parsing values for non-boolean arguments
570
+ * (e.g. port number for the dev server).
340
571
  *
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;
572
+ * @param flags a ConfigFlags object to which parsed arguments will be added
573
+ * @param args an array of command-line arguments to parse
574
+ */
575
+ const parseArgs = (flags, args) => {
576
+ BOOLEAN_CLI_ARGS.forEach((argName) => parseBooleanArg(flags, args, argName));
577
+ STRING_CLI_ARGS.forEach((argName) => parseStringArg(flags, args, argName));
578
+ NUMBER_CLI_ARGS.forEach((argName) => parseNumberArg(flags, args, argName));
579
+ STRING_NUMBER_CLI_ARGS.forEach((argName) => parseStringNumberArg(flags, args, argName));
580
+ LOG_LEVEL_CLI_ARGS.forEach((argName) => parseLogLevelArg(flags, args, argName));
581
+ };
582
+ /**
583
+ * Parse a boolean CLI argument. For these, we support the following formats:
584
+ *
585
+ * - `--booleanArg`
586
+ * - `--boolean-arg`
587
+ * - `--noBooleanArg`
588
+ * - `--no-boolean-arg`
589
+ *
590
+ * The final two variants should be parsed to a value of `false` on the config
591
+ * object.
592
+ *
593
+ * @param flags the config flags object, while we'll modify
594
+ * @param args our CLI arguments
595
+ * @param configCaseName the argument we want to look at right now
596
+ */
597
+ const parseBooleanArg = (flags, args, configCaseName) => {
598
+ // we support both dash-case and PascalCase versions of the parameter
599
+ // argName is 'configCase' version which can be found in BOOLEAN_ARG_OPTS
600
+ const alias = CLI_ARG_ALIASES[configCaseName];
601
+ const dashCaseName = toDashCase(configCaseName);
602
+ if (typeof flags[configCaseName] !== 'boolean') {
603
+ flags[configCaseName] = null;
604
+ }
605
+ args.forEach((cmdArg) => {
606
+ let value;
607
+ if (cmdArg === `--${configCaseName}` || cmdArg === `--${dashCaseName}`) {
608
+ value = true;
351
609
  }
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;
610
+ else if (cmdArg === `--no-${dashCaseName}` || cmdArg === `--no${dashToPascalCase(dashCaseName)}`) {
611
+ value = false;
380
612
  }
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
- }
613
+ else if (alias && cmdArg === `-${alias}`) {
614
+ value = true;
615
+ }
616
+ if (value !== undefined && cmdArg !== undefined) {
617
+ flags[configCaseName] = value;
618
+ flags.knownArgs.push(cmdArg);
417
619
  }
418
620
  });
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;
621
+ };
622
+ /**
623
+ * Parse a string CLI argument
624
+ *
625
+ * @param flags the config flags object, while we'll modify
626
+ * @param args our CLI arguments
627
+ * @param configCaseName the argument we want to look at right now
628
+ */
629
+ const parseStringArg = (flags, args, configCaseName) => {
630
+ if (typeof flags[configCaseName] !== 'string') {
631
+ flags[configCaseName] = null;
632
+ }
633
+ const { value, matchingArg } = getValue(args, configCaseName);
634
+ if (value !== undefined && matchingArg !== undefined) {
635
+ flags[configCaseName] = value;
636
+ flags.knownArgs.push(matchingArg);
637
+ flags.knownArgs.push(value);
638
+ }
639
+ };
640
+ /**
641
+ * Parse a number CLI argument
642
+ *
643
+ * @param flags the config flags object, while we'll modify
644
+ * @param args our CLI arguments
645
+ * @param configCaseName the argument we want to look at right now
646
+ */
647
+ const parseNumberArg = (flags, args, configCaseName) => {
648
+ if (typeof flags[configCaseName] !== 'number') {
649
+ flags[configCaseName] = null;
650
+ }
651
+ const { value, matchingArg } = getValue(args, configCaseName);
652
+ if (value !== undefined && matchingArg !== undefined) {
653
+ flags[configCaseName] = parseInt(value, 10);
654
+ flags.knownArgs.push(matchingArg);
655
+ flags.knownArgs.push(value);
656
+ }
657
+ };
658
+ /**
659
+ * Parse a CLI argument which may be either a string or a number
660
+ *
661
+ * @param flags the config flags object, while we'll modify
662
+ * @param args our CLI arguments
663
+ * @param configCaseName the argument we want to look at right now
664
+ */
665
+ const parseStringNumberArg = (flags, args, configCaseName) => {
666
+ if (!['number', 'string'].includes(typeof flags[configCaseName])) {
667
+ flags[configCaseName] = null;
668
+ }
669
+ const { value, matchingArg } = getValue(args, configCaseName);
670
+ if (value !== undefined && matchingArg !== undefined) {
671
+ if (CLI_ARG_STRING_REGEX.test(value)) {
672
+ // if it matches the regex we treat it like a string
673
+ flags[configCaseName] = value;
424
674
  }
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]);
675
+ else {
676
+ // it was a number, great!
677
+ flags[configCaseName] = Number(value);
678
+ }
679
+ flags.knownArgs.push(matchingArg);
680
+ flags.knownArgs.push(value);
681
+ }
682
+ };
683
+ /**
684
+ * We use this regular expression to detect CLI parameters which
685
+ * should be parsed as string values (as opposed to numbers) for
686
+ * the argument types for which we support both a string and a
687
+ * number value.
688
+ *
689
+ * The regex tests for the presence of at least one character which is
690
+ * _not_ a digit (`\d`), a period (`\.`), or one of the characters `"e"`,
691
+ * `"E"`, `"+"`, or `"-"` (the latter four characters are necessary to
692
+ * support the admittedly unlikely use of scientific notation, like `"4e+0"`
693
+ * for `4`).
694
+ *
695
+ * Thus we'll match a string like `"50%"`, but not a string like `"50"` or
696
+ * `"5.0"`. If it matches a given string we conclude that the string should
697
+ * be parsed as a string literal, rather than using `Number` to convert it
698
+ * to a number.
699
+ */
700
+ const CLI_ARG_STRING_REGEX = /[^\d\.Ee\+\-]+/g;
701
+ /**
702
+ * Parse a LogLevel CLI argument. These can be only a specific
703
+ * set of strings, so this function takes care of validating that
704
+ * the value is correct.
705
+ *
706
+ * @param flags the config flags object, while we'll modify
707
+ * @param args our CLI arguments
708
+ * @param configCaseName the argument we want to look at right now
709
+ */
710
+ const parseLogLevelArg = (flags, args, configCaseName) => {
711
+ if (typeof flags[configCaseName] !== 'string') {
712
+ flags[configCaseName] = null;
713
+ }
714
+ const { value, matchingArg } = getValue(args, configCaseName);
715
+ if (value !== undefined && matchingArg !== undefined && isLogLevel(value)) {
716
+ flags[configCaseName] = value;
717
+ flags.knownArgs.push(matchingArg);
718
+ flags.knownArgs.push(value);
719
+ }
720
+ };
721
+ /**
722
+ * Helper for pulling values out from the raw array of CLI arguments. This logic
723
+ * is shared between a few different types of CLI args.
724
+ *
725
+ * We look for arguments in the following formats:
726
+ *
727
+ * - `--my-cli-argument value`
728
+ * - `--my-cli-argument=value`
729
+ * - `--myCliArgument value`
730
+ * - `--myCliArgument=value`
731
+ *
732
+ * We also check for shortened aliases, which we define for a few arguments.
733
+ *
734
+ * @param args the CLI args we're dealing with
735
+ * @param configCaseName the ConfigFlag key which we're looking to pull out a value for
736
+ * @returns the value for the flag as well as the exact string which it matched from
737
+ * the user input.
738
+ */
739
+ const getValue = (args, configCaseName) => {
740
+ // for some CLI args we have a short alias, like 'c' for 'config'
741
+ const alias = CLI_ARG_ALIASES[configCaseName];
742
+ // we support supplying arguments in both dash-case and configCase
743
+ // for ease of use
744
+ const dashCaseName = toDashCase(configCaseName);
745
+ let value;
746
+ let matchingArg;
747
+ args.forEach((arg, i) => {
748
+ if (arg.startsWith(`--${dashCaseName}=`) || arg.startsWith(`--${configCaseName}=`)) {
749
+ value = getEqualsValue(arg);
750
+ matchingArg = arg;
751
+ }
752
+ else if (arg === `--${dashCaseName}` || arg === `--${configCaseName}`) {
753
+ value = args[i + 1];
754
+ matchingArg = arg;
755
+ }
756
+ else if (alias) {
757
+ if (arg.startsWith(`-${alias}=`)) {
758
+ value = getEqualsValue(arg);
759
+ matchingArg = arg;
446
760
  }
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
- }
761
+ else if (arg === `-${alias}`) {
762
+ value = args[i + 1];
763
+ matchingArg = arg;
458
764
  }
459
765
  }
460
766
  });
767
+ return { value, matchingArg };
461
768
  };
462
- const configCase = (prop) => {
463
- prop = dashToPascalCase(prop);
464
- return prop.charAt(0).toLowerCase() + prop.slice(1);
465
- };
466
- const BOOLEAN_ARG_OPTS = [
467
- 'build',
468
- 'cache',
469
- 'check-version',
470
- 'ci',
471
- 'compare',
472
- 'debug',
473
- 'dev',
474
- 'devtools',
475
- 'docs',
476
- 'e2e',
477
- 'es5',
478
- 'esm',
479
- 'headless',
480
- 'help',
481
- 'log',
482
- 'open',
483
- 'prerender',
484
- 'prerender-external',
485
- 'prod',
486
- 'profile',
487
- 'service-worker',
488
- 'screenshot',
489
- 'serve',
490
- 'skip-node-check',
491
- 'spec',
492
- 'ssr',
493
- 'stats',
494
- 'update-screenshot',
495
- 'verbose',
496
- 'version',
497
- 'watch',
498
- ];
499
- const NUMBER_ARG_OPTS = ['max-workers', 'port'];
500
- const STRING_ARG_OPTS = [
501
- 'address',
502
- 'config',
503
- 'docs-json',
504
- 'emulate',
505
- 'log-level',
506
- 'root',
507
- 'screenshot-connector',
508
- ];
509
- const ARG_OPTS_ALIASES = {
510
- config: 'c',
511
- help: 'h',
512
- port: 'p',
513
- version: 'v',
514
- };
769
+ /**
770
+ * When a parameter is set in the format `--foobar=12` at the CLI (as opposed to
771
+ * `--foobar 12`) we want to get the value after the `=` sign
772
+ *
773
+ * @param commandArgument the arg in question
774
+ * @returns the value after the `=`
775
+ */
776
+ const getEqualsValue = (commandArgument) => commandArgument.split('=').slice(1).join('=');
777
+ /**
778
+ * Small helper for getting type-system-level assurance that a `string` can be
779
+ * narrowed to a `LogLevel`
780
+ *
781
+ * @param maybeLogLevel the string to check
782
+ * @returns whether this is a `LogLevel`
783
+ */
784
+ const isLogLevel = (maybeLogLevel) =>
785
+ // unfortunately `includes` is typed on `ReadonlyArray<T>` as `(el: T):
786
+ // boolean` so a `string` cannot be passed to `includes` on a
787
+ // `ReadonlyArray` 😢 thus we `as any`
788
+ //
789
+ // see microsoft/TypeScript#31018 for some discussion of this
790
+ LOG_LEVELS.includes(maybeLogLevel);
515
791
  const getNpmConfigEnvArgs = (sys) => {
516
792
  // process.env.npm_config_argv
517
793
  // {"remain":["4444"],"cooked":["run","serve","--port","4444"],"original":["run","serve","--port","4444"]}
@@ -532,7 +808,7 @@ const getNpmConfigEnvArgs = (sys) => {
532
808
  const dependencies = [
533
809
  {
534
810
  name: "@stencil/core",
535
- version: "2.17.0",
811
+ version: "2.17.1",
536
812
  main: "compiler/stencil.js",
537
813
  resources: [
538
814
  "package.json",
@@ -857,12 +1133,11 @@ const tryFn = async (fn, ...args) => {
857
1133
  }
858
1134
  return null;
859
1135
  };
860
- const isInteractive = (sys, config, object) => {
861
- var _a;
1136
+ const isInteractive = (sys, flags, object) => {
862
1137
  const terminalInfo = object ||
863
1138
  Object.freeze({
864
1139
  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),
1140
+ ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!flags.ci,
866
1141
  });
867
1142
  return terminalInfo.tty && !terminalInfo.ci;
868
1143
  };
@@ -887,19 +1162,19 @@ async function readJson(sys, path) {
887
1162
  }
888
1163
  /**
889
1164
  * Does the command have the debug flag?
890
- * @param config The config passed into the Stencil command
1165
+ * @param flags The configuration flags passed into the Stencil command
891
1166
  * @returns true if --debug has been passed, otherwise false
892
1167
  */
893
- function hasDebug(config) {
894
- return config.flags.debug;
1168
+ function hasDebug(flags) {
1169
+ return flags.debug;
895
1170
  }
896
1171
  /**
897
1172
  * Does the command have the verbose and debug flags?
898
- * @param config The config passed into the Stencil command
1173
+ * @param flags The configuration flags passed into the Stencil command
899
1174
  * @returns true if both --debug and --verbose have been passed, otherwise false
900
1175
  */
901
- function hasVerbose(config) {
902
- return config.flags.verbose && hasDebug(config);
1176
+ function hasVerbose(flags) {
1177
+ return flags.verbose && hasDebug(flags);
903
1178
  }
904
1179
 
905
1180
  /**
@@ -910,7 +1185,7 @@ function hasVerbose(config) {
910
1185
  * @returns true if telemetry should be sent, false otherwise
911
1186
  */
912
1187
  async function shouldTrack(config, sys, ci) {
913
- return !ci && isInteractive(sys, config) && (await checkTelemetry(sys));
1188
+ return !ci && isInteractive(sys, config.flags) && (await checkTelemetry(sys));
914
1189
  }
915
1190
 
916
1191
  const isTest$1 = () => process.env.JEST_WORKER_ID !== undefined;
@@ -981,11 +1256,10 @@ const WWW = 'www';
981
1256
  *
982
1257
  * @param sys The system where the command is invoked
983
1258
  * @param config The config passed into the Stencil command
984
- * @param logger The tool used to do logging
985
1259
  * @param coreCompiler The compiler used to do builds
986
1260
  * @param result The results of a compiler build.
987
1261
  */
988
- async function telemetryBuildFinishedAction(sys, config, logger, coreCompiler, result) {
1262
+ async function telemetryBuildFinishedAction(sys, config, coreCompiler, result) {
989
1263
  const tracking = await shouldTrack(config, sys, config.flags.ci);
990
1264
  if (!tracking) {
991
1265
  return;
@@ -993,21 +1267,19 @@ async function telemetryBuildFinishedAction(sys, config, logger, coreCompiler, r
993
1267
  const component_count = Object.keys(result.componentGraph).length;
994
1268
  const data = await prepareData(coreCompiler, config, sys, result.duration, component_count);
995
1269
  await sendMetric(sys, config, 'stencil_cli_command', data);
996
- logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
1270
+ config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
997
1271
  }
998
1272
  /**
999
1273
  * A function to wrap a compiler task function around. Will send telemetry if, and only if, the machine allows.
1000
1274
  *
1001
1275
  * @param sys The system where the command is invoked
1002
1276
  * @param config The config passed into the Stencil command
1003
- * @param logger The tool used to do logging
1004
1277
  * @param coreCompiler The compiler used to do builds
1005
1278
  * @param action A Promise-based function to call in order to get the duration of any given command.
1006
1279
  * @returns void
1007
1280
  */
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));
1281
+ async function telemetryAction(sys, config, coreCompiler, action) {
1282
+ const tracking = await shouldTrack(config, sys, !!config.flags.ci);
1011
1283
  let duration = undefined;
1012
1284
  let error;
1013
1285
  if (action) {
@@ -1027,7 +1299,7 @@ async function telemetryAction(sys, config, logger, coreCompiler, action) {
1027
1299
  }
1028
1300
  const data = await prepareData(coreCompiler, config, sys, duration);
1029
1301
  await sendMetric(sys, config, 'stencil_cli_command', data);
1030
- logger.debug(`${logger.blue('Telemetry')}: ${logger.gray(JSON.stringify(data))}`);
1302
+ config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
1031
1303
  if (error) {
1032
1304
  throw error;
1033
1305
  }
@@ -1195,7 +1467,7 @@ async function getInstalledPackages(sys, config) {
1195
1467
  return { packages, packagesNoVersions };
1196
1468
  }
1197
1469
  catch (err) {
1198
- hasDebug(config) && console.error(err);
1470
+ hasDebug(config.flags) && console.error(err);
1199
1471
  return { packages, packagesNoVersions };
1200
1472
  }
1201
1473
  }
@@ -1297,15 +1569,15 @@ async function sendTelemetry(sys, config, data) {
1297
1569
  },
1298
1570
  body: JSON.stringify(body),
1299
1571
  });
1300
- hasVerbose(config) &&
1572
+ hasVerbose(config.flags) &&
1301
1573
  console.debug('\nSent %O metric to events service (status: %O)', data.name, response.status, '\n');
1302
1574
  if (response.status !== 204) {
1303
- hasVerbose(config) &&
1575
+ hasVerbose(config.flags) &&
1304
1576
  console.debug('\nBad response from events service. Request body: %O', response.body.toString(), '\n');
1305
1577
  }
1306
1578
  }
1307
1579
  catch (e) {
1308
- hasVerbose(config) && console.debug('Telemetry request failed:', e);
1580
+ hasVerbose(config.flags) && console.debug('Telemetry request failed:', e);
1309
1581
  }
1310
1582
  }
1311
1583
  /**
@@ -1362,7 +1634,7 @@ const taskBuild = async (coreCompiler, config, sys) => {
1362
1634
  const results = await compiler.build();
1363
1635
  // TODO(STENCIL-148) make this parameter no longer optional, remove the surrounding if statement
1364
1636
  if (sys) {
1365
- await telemetryBuildFinishedAction(sys, config, config.logger, coreCompiler, results);
1637
+ await telemetryBuildFinishedAction(sys, config, coreCompiler, results);
1366
1638
  }
1367
1639
  await compiler.destroy();
1368
1640
  if (results.hasError) {
@@ -1401,6 +1673,7 @@ const IS_NODE_ENV = typeof global !== 'undefined' &&
1401
1673
  !!global.process &&
1402
1674
  typeof __filename === 'string' &&
1403
1675
  (!global.origin || typeof global.origin !== 'string');
1676
+ const IS_BROWSER_ENV = typeof location !== 'undefined' && typeof navigator !== 'undefined' && typeof XMLHttpRequest !== 'undefined';
1404
1677
 
1405
1678
  /**
1406
1679
  * Task to generate component boilerplate and write it to disk. This task can
@@ -1596,7 +1869,8 @@ export class ${toPascalCase(tagName)} {
1596
1869
  `;
1597
1870
  };
1598
1871
  /**
1599
- * Get the boilerplate for style.
1872
+ * Get the boilerplate for style for a generated component
1873
+ * @returns a boilerplate CSS block
1600
1874
  */
1601
1875
  const getStyleUrlBoilerplate = () => `:host {
1602
1876
  display: block;
@@ -1650,10 +1924,17 @@ describe('${tagName}', () => {
1650
1924
  */
1651
1925
  const toPascalCase = (str) => str.split('-').reduce((res, part) => res + part[0].toUpperCase() + part.slice(1), '');
1652
1926
 
1653
- const taskTelemetry = async (config, sys, logger) => {
1927
+ /**
1928
+ * Entrypoint for the Telemetry task
1929
+ * @param flags configuration flags provided to Stencil when a task was called (either this task or a task that invokes
1930
+ * telemetry)
1931
+ * @param sys the abstraction for interfacing with the operating system
1932
+ * @param logger a logging implementation to log the results out to the user
1933
+ */
1934
+ const taskTelemetry = async (flags, sys, logger) => {
1654
1935
  const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
1655
- const isEnabling = config.flags.args.includes('on');
1656
- const isDisabling = config.flags.args.includes('off');
1936
+ const isEnabling = flags.args.includes('on');
1937
+ const isDisabling = flags.args.includes('off');
1657
1938
  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
1939
  const THANK_YOU = `Thank you for helping to make Stencil better! 💖`;
1659
1940
  const ENABLED_MESSAGE = `${logger.green('Enabled')}. ${THANK_YOU}\n\n`;
@@ -1682,7 +1963,14 @@ const taskTelemetry = async (config, sys, logger) => {
1682
1963
  `);
1683
1964
  };
1684
1965
 
1685
- const taskHelp = async (config, logger, sys) => {
1966
+ /**
1967
+ * Entrypoint for the Help task, providing Stencil usage context to the user
1968
+ * @param flags configuration flags provided to Stencil when a task was call (either this task or a task that invokes
1969
+ * telemetry)
1970
+ * @param logger a logging implementation to log the results out to the user
1971
+ * @param sys the abstraction for interfacing with the operating system
1972
+ */
1973
+ const taskHelp = async (flags, logger, sys) => {
1686
1974
  const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
1687
1975
  console.log(`
1688
1976
  ${logger.bold('Build:')} ${logger.dim('Build components for development or production.')}
@@ -1715,7 +2003,7 @@ const taskHelp = async (config, logger, sys) => {
1715
2003
  `);
1716
2004
  // TODO(STENCIL-148) make this parameter no longer optional, remove the surrounding if statement
1717
2005
  if (sys) {
1718
- await taskTelemetry(config, sys, logger);
2006
+ await taskTelemetry(flags, sys, logger);
1719
2007
  }
1720
2008
  console.log(`
1721
2009
  ${logger.bold('Examples:')}
@@ -1772,6 +2060,10 @@ const taskServe = async (config) => {
1772
2060
  });
1773
2061
  };
1774
2062
 
2063
+ /**
2064
+ * Entrypoint for any Stencil tests
2065
+ * @param config a validated Stencil configuration entity
2066
+ */
1775
2067
  const taskTest = async (config) => {
1776
2068
  if (!IS_NODE_ENV) {
1777
2069
  config.logger.error(`"test" command is currently only implemented for a NodeJS environment`);
@@ -1818,6 +2110,95 @@ const taskTest = async (config) => {
1818
2110
  }
1819
2111
  };
1820
2112
 
2113
+ /**
2114
+ * Creates an instance of a logger
2115
+ * @returns the new logger instance
2116
+ */
2117
+ const createLogger = () => {
2118
+ let useColors = IS_BROWSER_ENV;
2119
+ let level = 'info';
2120
+ return {
2121
+ enableColors: (uc) => (useColors = uc),
2122
+ getLevel: () => level,
2123
+ setLevel: (l) => (level = l),
2124
+ emoji: (e) => e,
2125
+ info: console.log.bind(console),
2126
+ warn: console.warn.bind(console),
2127
+ error: console.error.bind(console),
2128
+ debug: console.debug.bind(console),
2129
+ red: (msg) => msg,
2130
+ green: (msg) => msg,
2131
+ yellow: (msg) => msg,
2132
+ blue: (msg) => msg,
2133
+ magenta: (msg) => msg,
2134
+ cyan: (msg) => msg,
2135
+ gray: (msg) => msg,
2136
+ bold: (msg) => msg,
2137
+ dim: (msg) => msg,
2138
+ bgRed: (msg) => msg,
2139
+ createTimeSpan: (_startMsg, _debug = false) => ({
2140
+ duration: () => 0,
2141
+ finish: () => 0,
2142
+ }),
2143
+ printDiagnostics(diagnostics) {
2144
+ diagnostics.forEach((diagnostic) => logDiagnostic(diagnostic, useColors));
2145
+ },
2146
+ };
2147
+ };
2148
+ const logDiagnostic = (diagnostic, useColors) => {
2149
+ let color = BLUE;
2150
+ let prefix = 'Build';
2151
+ let msg = '';
2152
+ if (diagnostic.level === 'error') {
2153
+ color = RED;
2154
+ prefix = 'Error';
2155
+ }
2156
+ else if (diagnostic.level === 'warn') {
2157
+ color = YELLOW;
2158
+ prefix = 'Warning';
2159
+ }
2160
+ if (diagnostic.header) {
2161
+ prefix = diagnostic.header;
2162
+ }
2163
+ const filePath = diagnostic.relFilePath || diagnostic.absFilePath;
2164
+ if (filePath) {
2165
+ msg += filePath;
2166
+ if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > 0) {
2167
+ msg += ', line ' + diagnostic.lineNumber;
2168
+ if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > 0) {
2169
+ msg += ', column ' + diagnostic.columnNumber;
2170
+ }
2171
+ }
2172
+ msg += '\n';
2173
+ }
2174
+ msg += diagnostic.messageText;
2175
+ if (diagnostic.lines && diagnostic.lines.length > 0) {
2176
+ diagnostic.lines.forEach((l) => {
2177
+ msg += '\n' + l.lineNumber + ': ' + l.text;
2178
+ });
2179
+ msg += '\n';
2180
+ }
2181
+ if (useColors) {
2182
+ const styledPrefix = [
2183
+ '%c' + prefix,
2184
+ `background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`,
2185
+ ];
2186
+ console.log(...styledPrefix, msg);
2187
+ }
2188
+ else if (diagnostic.level === 'error') {
2189
+ console.error(msg);
2190
+ }
2191
+ else if (diagnostic.level === 'warn') {
2192
+ console.warn(msg);
2193
+ }
2194
+ else {
2195
+ console.log(msg);
2196
+ }
2197
+ };
2198
+ const YELLOW = `#f39c12`;
2199
+ const RED = `#c0392b`;
2200
+ const BLUE = `#3498db`;
2201
+
1821
2202
  const run = async (init) => {
1822
2203
  const { args, logger, sys } = init;
1823
2204
  try {
@@ -1833,7 +2214,7 @@ const run = async (init) => {
1833
2214
  sys.applyGlobalPatch(sys.getCurrentDirectory());
1834
2215
  }
1835
2216
  if (task === 'help' || flags.help) {
1836
- await taskHelp({ flags: { task: 'help', args }, outputTargets: [] }, logger, sys);
2217
+ await taskHelp({ task: 'help', args }, logger, sys);
1837
2218
  return;
1838
2219
  }
1839
2220
  startupLog(logger, task);
@@ -1859,7 +2240,7 @@ const run = async (init) => {
1859
2240
  startupLogVersion(logger, task, coreCompiler);
1860
2241
  loadedCompilerLog(sys, logger, flags, coreCompiler);
1861
2242
  if (task === 'info') {
1862
- await telemetryAction(sys, { flags: { task: 'info' }, outputTargets: [] }, logger, coreCompiler, async () => {
2243
+ await telemetryAction(sys, { flags: { task: 'info' }, logger }, coreCompiler, async () => {
1863
2244
  await taskInfo(coreCompiler, sys, logger);
1864
2245
  });
1865
2246
  return;
@@ -1882,7 +2263,7 @@ const run = async (init) => {
1882
2263
  sys.applyGlobalPatch(validated.config.rootDir);
1883
2264
  }
1884
2265
  await sys.ensureResources({ rootDir: validated.config.rootDir, logger, dependencies: dependencies });
1885
- await telemetryAction(sys, validated.config, logger, coreCompiler, async () => {
2266
+ await telemetryAction(sys, validated.config, coreCompiler, async () => {
1886
2267
  await runTask(coreCompiler, validated.config, task, sys);
1887
2268
  });
1888
2269
  }
@@ -1895,43 +2276,45 @@ const run = async (init) => {
1895
2276
  }
1896
2277
  };
1897
2278
  const runTask = async (coreCompiler, config, task, sys) => {
1898
- config.flags = config.flags || { task };
1899
- config.outputTargets = config.outputTargets || [];
2279
+ var _a, _b;
2280
+ const logger = (_a = config.logger) !== null && _a !== void 0 ? _a : createLogger();
2281
+ const strictConfig = { ...config, flags: (_b = { ...config.flags }) !== null && _b !== void 0 ? _b : { task }, logger };
2282
+ strictConfig.outputTargets = strictConfig.outputTargets || [];
1900
2283
  switch (task) {
1901
2284
  case 'build':
1902
- await taskBuild(coreCompiler, config, sys);
2285
+ await taskBuild(coreCompiler, strictConfig, sys);
1903
2286
  break;
1904
2287
  case 'docs':
1905
- await taskDocs(coreCompiler, config);
2288
+ await taskDocs(coreCompiler, strictConfig);
1906
2289
  break;
1907
2290
  case 'generate':
1908
2291
  case 'g':
1909
- await taskGenerate(coreCompiler, config);
2292
+ await taskGenerate(coreCompiler, strictConfig);
1910
2293
  break;
1911
2294
  case 'help':
1912
- await taskHelp(config, config.logger, sys);
2295
+ await taskHelp(strictConfig.flags, strictConfig.logger, sys);
1913
2296
  break;
1914
2297
  case 'prerender':
1915
- await taskPrerender(coreCompiler, config);
2298
+ await taskPrerender(coreCompiler, strictConfig);
1916
2299
  break;
1917
2300
  case 'serve':
1918
- await taskServe(config);
2301
+ await taskServe(strictConfig);
1919
2302
  break;
1920
2303
  case 'telemetry':
1921
2304
  // TODO(STENCIL-148) make this parameter no longer optional, remove the surrounding if statement
1922
2305
  if (sys) {
1923
- await taskTelemetry(config, sys, config.logger);
2306
+ await taskTelemetry(strictConfig.flags, sys, strictConfig.logger);
1924
2307
  }
1925
2308
  break;
1926
2309
  case 'test':
1927
- await taskTest(config);
2310
+ await taskTest(strictConfig);
1928
2311
  break;
1929
2312
  case 'version':
1930
2313
  console.log(coreCompiler.version);
1931
2314
  break;
1932
2315
  default:
1933
- config.logger.error(`${config.logger.emoji('❌ ')}Invalid stencil command, please see the options below:`);
1934
- await taskHelp(config, config.logger, sys);
2316
+ strictConfig.logger.error(`${strictConfig.logger.emoji('❌ ')}Invalid stencil command, please see the options below:`);
2317
+ await taskHelp(strictConfig.flags, strictConfig.logger, sys);
1935
2318
  return config.sys.exit(1);
1936
2319
  }
1937
2320
  };