@stencil/core 2.19.2 → 3.0.0-alpha.0

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 (42) hide show
  1. package/bin/stencil +3 -3
  2. package/cli/config-flags.d.ts +31 -19
  3. package/cli/index.cjs +358 -190
  4. package/cli/index.d.ts +3 -3
  5. package/cli/index.js +358 -190
  6. package/cli/package.json +1 -1
  7. package/compiler/package.json +1 -1
  8. package/compiler/stencil.js +559 -834
  9. package/compiler/stencil.min.js +2 -2
  10. package/dependencies.json +1 -1
  11. package/dev-server/client/index.js +1 -1
  12. package/dev-server/client/package.json +1 -1
  13. package/dev-server/connector.html +2 -2
  14. package/dev-server/index.js +1 -1
  15. package/dev-server/package.json +1 -1
  16. package/dev-server/server-process.js +2 -2
  17. package/internal/app-data/package.json +1 -1
  18. package/internal/client/css-shim.js +1 -1
  19. package/internal/client/dom.js +1 -1
  20. package/internal/client/index.js +1 -1
  21. package/internal/client/package.json +1 -1
  22. package/internal/client/patch-browser.js +1 -1
  23. package/internal/client/patch-esm.js +1 -1
  24. package/internal/client/shadow-css.js +1 -1
  25. package/internal/hydrate/package.json +1 -1
  26. package/internal/hydrate/runner.d.ts +1 -1
  27. package/internal/package.json +1 -1
  28. package/internal/stencil-public-compiler.d.ts +31 -17
  29. package/internal/stencil-public-runtime.d.ts +12 -12
  30. package/internal/testing/package.json +1 -1
  31. package/mock-doc/index.cjs +6 -6
  32. package/mock-doc/index.js +6 -6
  33. package/mock-doc/package.json +1 -1
  34. package/package.json +15 -15
  35. package/screenshot/package.json +1 -1
  36. package/sys/node/autoprefixer.js +2 -2
  37. package/sys/node/index.js +11 -11
  38. package/sys/node/package.json +1 -1
  39. package/sys/node/worker.js +1 -1
  40. package/testing/index.js +15 -13
  41. package/testing/package.json +1 -1
  42. package/testing/puppeteer/puppeteer-declarations.d.ts +1 -27
package/cli/index.js CHANGED
@@ -1,18 +1,6 @@
1
1
  /*!
2
- Stencil CLI v2.19.2 | MIT Licensed | https://stenciljs.com
2
+ Stencil CLI v3.0.0-alpha.0 | MIT Licensed | https://stenciljs.com
3
3
  */
4
- /**
5
- * Convert a string from PascalCase to dash-case
6
- *
7
- * @param str the string to convert
8
- * @returns a converted string
9
- */
10
- const toDashCase = (str) => str
11
- .replace(/([A-Z0-9])/g, (match) => ` ${match[0]}`)
12
- .trim()
13
- .split(' ')
14
- .join('-')
15
- .toLowerCase();
16
4
  /**
17
5
  * Convert a string from dash-case / kebab-case to PascalCase (or CamelCase,
18
6
  * or whatever you call it!)
@@ -25,6 +13,16 @@ const dashToPascalCase = (str) => str
25
13
  .split('-')
26
14
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
27
15
  .join('');
16
+ /**
17
+ * Convert a string to 'camelCase'
18
+ *
19
+ * @param str the string to convert
20
+ * @returns the converted string
21
+ */
22
+ const toCamelCase = (str) => {
23
+ const pascalCase = dashToPascalCase(str);
24
+ return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
25
+ };
28
26
  const isFunction = (v) => typeof v === 'function';
29
27
  const isString = (v) => typeof v === 'string';
30
28
 
@@ -336,7 +334,7 @@ const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
336
334
  /**
337
335
  * All the Boolean options supported by the Stencil CLI
338
336
  */
339
- const BOOLEAN_CLI_ARGS = [
337
+ const BOOLEAN_CLI_FLAGS = [
340
338
  'build',
341
339
  'cache',
342
340
  'checkVersion',
@@ -419,7 +417,7 @@ const BOOLEAN_CLI_ARGS = [
419
417
  /**
420
418
  * All the Number options supported by the Stencil CLI
421
419
  */
422
- const NUMBER_CLI_ARGS = [
420
+ const NUMBER_CLI_FLAGS = [
423
421
  'port',
424
422
  // JEST CLI ARGS
425
423
  'maxConcurrency',
@@ -428,7 +426,7 @@ const NUMBER_CLI_ARGS = [
428
426
  /**
429
427
  * All the String options supported by the Stencil CLI
430
428
  */
431
- const STRING_CLI_ARGS = [
429
+ const STRING_CLI_FLAGS = [
432
430
  'address',
433
431
  'config',
434
432
  'docsApi',
@@ -467,7 +465,8 @@ const STRING_CLI_ARGS = [
467
465
  'testURL',
468
466
  'timers',
469
467
  'transform',
470
- // ARRAY ARGS
468
+ ];
469
+ const STRING_ARRAY_CLI_FLAGS = [
471
470
  'collectCoverageOnlyFrom',
472
471
  'coveragePathIgnorePatterns',
473
472
  'coverageReporters',
@@ -496,7 +495,7 @@ const STRING_CLI_ARGS = [
496
495
  * `maxWorkers` is an argument which is used both by Stencil _and_ by Jest,
497
496
  * which means that we need to support parsing both string and number values.
498
497
  */
499
- const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
498
+ const STRING_NUMBER_CLI_FLAGS = ['maxWorkers'];
500
499
  /**
501
500
  * All the LogLevel-type options supported by the Stencil CLI
502
501
  *
@@ -504,16 +503,21 @@ const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
504
503
  * but this approach lets us make sure that we're handling all
505
504
  * our arguments in a type-safe way.
506
505
  */
507
- const LOG_LEVEL_CLI_ARGS = ['logLevel'];
506
+ const LOG_LEVEL_CLI_FLAGS = ['logLevel'];
508
507
  /**
509
508
  * For a small subset of CLI options we support a short alias e.g. `'h'` for `'help'`
510
509
  */
511
- const CLI_ARG_ALIASES = {
512
- config: 'c',
513
- help: 'h',
514
- port: 'p',
515
- version: 'v',
510
+ const CLI_FLAG_ALIASES = {
511
+ c: 'config',
512
+ h: 'help',
513
+ p: 'port',
514
+ v: 'version',
516
515
  };
516
+ /**
517
+ * A regular expression which can be used to match a CLI flag for one of our
518
+ * short aliases.
519
+ */
520
+ const CLI_FLAG_REGEX = new RegExp(`^-[chpv]{1}$`);
517
521
  /**
518
522
  * Helper function for initializing a `ConfigFlags` object. Provide any overrides
519
523
  * for default values and off you go!
@@ -536,18 +540,22 @@ const createConfigFlags = (init = {}) => {
536
540
  * Parse command line arguments into a structured `ConfigFlags` object
537
541
  *
538
542
  * @param args an array of CLI flags
539
- * @param _sys an optional compiler system
540
543
  * @returns a structured ConfigFlags object
541
544
  */
542
- const parseFlags = (args, _sys) => {
543
- // TODO(STENCIL-509): remove the _sys parameter here ^^ (for v3)
545
+ const parseFlags = (args) => {
544
546
  const flags = createConfigFlags();
545
547
  // cmd line has more priority over npm scripts cmd
546
548
  flags.args = Array.isArray(args) ? args.slice() : [];
547
549
  if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
548
550
  flags.task = flags.args[0];
551
+ // if the first argument was a "task" (like `build`, `test`, etc) then
552
+ // we go on to parse the _rest_ of the CLI args
553
+ parseArgs(flags, args.slice(1));
554
+ }
555
+ else {
556
+ // we didn't find a leading flag, so we should just parse them all
557
+ parseArgs(flags, flags.args);
549
558
  }
550
- parseArgs(flags, flags.args);
551
559
  if (flags.task != null) {
552
560
  const i = flags.args.indexOf(flags.task);
553
561
  if (i > -1) {
@@ -564,120 +572,259 @@ const parseFlags = (args, _sys) => {
564
572
  return flags;
565
573
  };
566
574
  /**
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).
575
+ * Parse the supported command line flags which are enumerated in the
576
+ * `config-flags` module. Handles leading dashes on arguments, aliases that are
577
+ * defined for a small number of arguments, and parsing values for non-boolean
578
+ * arguments (e.g. port number for the dev server).
579
+ *
580
+ * This parses the following grammar:
581
+ *
582
+ * CLIArguments → ""
583
+ * | CLITerm ( " " CLITerm )* ;
584
+ * CLITerm → EqualsArg
585
+ * | AliasEqualsArg
586
+ * | AliasArg
587
+ * | NegativeDashArg
588
+ * | NegativeArg
589
+ * | SimpleArg ;
590
+ * EqualsArg → "--" ArgName "=" CLIValue ;
591
+ * AliasEqualsArg → "-" AliasName "=" CLIValue ;
592
+ * AliasArg → "-" AliasName ( " " CLIValue )? ;
593
+ * NegativeDashArg → "--no-" ArgName ;
594
+ * NegativeArg → "--no" ArgName ;
595
+ * SimpleArg → "--" ArgName ( " " CLIValue )? ;
596
+ * ArgName → /^[a-zA-Z-]+$/ ;
597
+ * AliasName → /^[a-z]{1}$/ ;
598
+ * CLIValue → '"' /^[a-zA-Z0-9]+$/ '"'
599
+ * | /^[a-zA-Z0-9]+$/ ;
600
+ *
601
+ * There are additional constraints (not shown in the grammar for brevity's sake)
602
+ * on the type of `CLIValue` which will be associated with a particular argument.
603
+ * We enforce this by declaring lists of boolean, string, etc arguments and
604
+ * checking the types of values before setting them.
605
+ *
606
+ * We don't need to turn the list of CLI arg tokens into any kind of
607
+ * intermediate representation since we aren't concerned with doing anything
608
+ * other than setting the correct values on our ConfigFlags object. So we just
609
+ * parse the array of string arguments using a recursive-descent approach
610
+ * (which is not very deep since our grammar is pretty simple) and make the
611
+ * modifications we need to make to the {@link ConfigFlags} object as we go.
571
612
  *
572
613
  * @param flags a ConfigFlags object to which parsed arguments will be added
573
614
  * @param args an array of command-line arguments to parse
574
615
  */
575
616
  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));
617
+ const argsCopy = args.concat();
618
+ while (argsCopy.length > 0) {
619
+ // there are still unprocessed args to deal with
620
+ parseCLITerm(flags, argsCopy);
621
+ }
581
622
  };
582
623
  /**
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.
624
+ * Given an array of CLI arguments, parse it and perform a series of side
625
+ * effects (setting values on the provided `ConfigFlags` object).
592
626
  *
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
627
+ * @param flags a {@link ConfigFlags} object which is updated as we parse the CLI
628
+ * arguments
629
+ * @param args a list of args to work through. This function (and some functions
630
+ * it calls) calls `Array.prototype.shift` to get the next argument to look at,
631
+ * so this parameter will be modified.
596
632
  */
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;
609
- }
610
- else if (cmdArg === `--no-${dashCaseName}` || cmdArg === `--no${dashToPascalCase(dashCaseName)}`) {
611
- value = false;
612
- }
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);
619
- }
620
- });
633
+ const parseCLITerm = (flags, args) => {
634
+ // pull off the first arg from the argument array
635
+ const arg = args.shift();
636
+ // array is empty, we're done!
637
+ if (arg === undefined)
638
+ return;
639
+ // EqualsArg → "--" ArgName "=" CLIValue ;
640
+ if (arg.startsWith('--') && arg.includes('=')) {
641
+ // we're dealing with an EqualsArg, we have a special helper for that
642
+ const [originalArg, value] = parseEqualsArg(arg);
643
+ setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);
644
+ }
645
+ // AliasEqualsArg → "-" AliasName "=" CLIValue ;
646
+ else if (arg.startsWith('-') && arg.includes('=')) {
647
+ // we're dealing with an AliasEqualsArg, we have a special helper for that
648
+ const [originalArg, value] = parseEqualsArg(arg);
649
+ setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);
650
+ }
651
+ // AliasArg → "-" AliasName ( " " CLIValue )? ;
652
+ else if (CLI_FLAG_REGEX.test(arg)) {
653
+ // this is a short alias, like `-c` for Config
654
+ setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));
655
+ }
656
+ // NegativeDashArg → "--no-" ArgName ;
657
+ else if (arg.startsWith('--no-') && arg.length > '--no-'.length) {
658
+ // this is a `NegativeDashArg` term, so we need to normalize the negative
659
+ // flag name and then set an appropriate value
660
+ const normalized = normalizeNegativeFlagName(arg);
661
+ setCLIArg(flags, arg, normalized, '');
662
+ }
663
+ // NegativeArg → "--no" ArgName ;
664
+ else if (arg.startsWith('--no') &&
665
+ !readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeFlagName(arg)) &&
666
+ readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeNegativeFlagName(arg))) {
667
+ // possibly dealing with a `NegativeArg` here. There is a little ambiguity
668
+ // here because we have arguments that already begin with `no` like
669
+ // `notify`, so we need to test if a normalized form of the raw argument is
670
+ // a valid and supported boolean flag.
671
+ setCLIArg(flags, arg, normalizeNegativeFlagName(arg), '');
672
+ }
673
+ // SimpleArg → "--" ArgName ( " " CLIValue )? ;
674
+ else if (arg.startsWith('--') && arg.length > '--'.length) {
675
+ setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));
676
+ }
677
+ // if we get here it is not an argument in our list of supported arguments.
678
+ // This doesn't necessarily mean we want to report an error or anything
679
+ // though! Instead, with unknown / unrecognized arguments we stick them into
680
+ // the `unknownArgs` array, which is used when we pass CLI args to Jest, for
681
+ // instance. So we just return void here.
621
682
  };
622
683
  /**
623
- * Parse a string CLI argument
684
+ * Normalize a 'negative' flag name, just to do a little pre-processing before
685
+ * we pass it to `setCLIArg`.
624
686
  *
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
687
+ * @param flagName the flag name to normalize
688
+ * @returns a normalized flag name
628
689
  */
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
- }
690
+ const normalizeNegativeFlagName = (flagName) => {
691
+ const trimmed = flagName.replace(/^--no[-]?/, '');
692
+ return normalizeFlagName(trimmed.charAt(0).toLowerCase() + trimmed.slice(1));
639
693
  };
640
694
  /**
641
- * Parse a number CLI argument
695
+ * Normalize a flag name by:
696
+ *
697
+ * - replacing any leading dashes (`--foo` -> `foo`)
698
+ * - converting `dash-case` to camelCase (if necessary)
699
+ *
700
+ * Normalizing in this context basically means converting the various
701
+ * supported flag spelling variants to the variant defined in our lists of
702
+ * supported arguments (e.g. BOOLEAN_CLI_FLAGS, etc). So, for instance,
703
+ * `--log-level` should be converted to `logLevel`.
704
+ *
705
+ * @param flagName the flag name to normalize
706
+ * @returns a normalized flag name
642
707
  *
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
708
  */
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
- }
709
+ const normalizeFlagName = (flagName) => {
710
+ const trimmed = flagName.replace(/^-+/, '');
711
+ return trimmed.includes('-') ? toCamelCase(trimmed) : trimmed;
657
712
  };
658
713
  /**
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;
714
+ * Set a value on a provided {@link ConfigFlags} object, given an argument
715
+ * name and a raw string value. This function dispatches to other functions
716
+ * which make sure that the string value can be properly parsed into a JS
717
+ * runtime value of the right type (e.g. number, string, etc).
718
+ *
719
+ * @throws if a value cannot be parsed to the right type for a given flag
720
+ * @param flags a {@link ConfigFlags} object
721
+ * @param rawArg the raw argument name matched by the parser
722
+ * @param normalizedArg an argument with leading control characters (`--`,
723
+ * `--no-`, etc) removed
724
+ * @param value the raw value to be set onto the config flags object
725
+ */
726
+ const setCLIArg = (flags, rawArg, normalizedArg, value) => {
727
+ normalizedArg = dereferenceAlias(normalizedArg);
728
+ // We're setting a boolean!
729
+ if (readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizedArg)) {
730
+ flags[normalizedArg] =
731
+ typeof value === 'string'
732
+ ? Boolean(value)
733
+ : // no value was supplied, default to true
734
+ true;
735
+ flags.knownArgs.push(rawArg);
736
+ }
737
+ // We're setting a string!
738
+ else if (readOnlyArrayHasStringMember(STRING_CLI_FLAGS, normalizedArg)) {
739
+ if (typeof value === 'string') {
740
+ flags[normalizedArg] = value;
741
+ flags.knownArgs.push(rawArg);
742
+ flags.knownArgs.push(value);
743
+ }
744
+ else {
745
+ throwCLIParsingError(rawArg, 'expected a string argument but received nothing');
746
+ }
747
+ }
748
+ // We're setting a string, but it's one where the user can pass multiple values,
749
+ // like `--reporters="default" --reporters="jest-junit"`
750
+ else if (readOnlyArrayHasStringMember(STRING_ARRAY_CLI_FLAGS, normalizedArg)) {
751
+ if (typeof value === 'string') {
752
+ if (!Array.isArray(flags[normalizedArg])) {
753
+ flags[normalizedArg] = [];
754
+ }
755
+ const targetArray = flags[normalizedArg];
756
+ // this is irritating, but TS doesn't know that the `!Array.isArray`
757
+ // check above guarantees we have an array to work with here, and it
758
+ // doesn't want to narrow the type of `flags[normalizedArg]`, so we need
759
+ // to grab a reference to that array and then `Array.isArray` that. Bah!
760
+ if (Array.isArray(targetArray)) {
761
+ targetArray.push(value);
762
+ flags.knownArgs.push(rawArg);
763
+ flags.knownArgs.push(value);
764
+ }
765
+ }
766
+ else {
767
+ throwCLIParsingError(rawArg, 'expected a string argument but received nothing');
768
+ }
668
769
  }
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;
770
+ // We're setting a number!
771
+ else if (readOnlyArrayHasStringMember(NUMBER_CLI_FLAGS, normalizedArg)) {
772
+ if (typeof value === 'string') {
773
+ const parsed = parseInt(value, 10);
774
+ if (isNaN(parsed)) {
775
+ throwNumberParsingError(rawArg, value);
776
+ }
777
+ else {
778
+ flags[normalizedArg] = parsed;
779
+ flags.knownArgs.push(rawArg);
780
+ flags.knownArgs.push(value);
781
+ }
674
782
  }
675
783
  else {
676
- // it was a number, great!
677
- flags[configCaseName] = Number(value);
784
+ throwCLIParsingError(rawArg, 'expected a number argument but received nothing');
785
+ }
786
+ }
787
+ // We're setting a value which could be either a string _or_ a number
788
+ else if (readOnlyArrayHasStringMember(STRING_NUMBER_CLI_FLAGS, normalizedArg)) {
789
+ if (typeof value === 'string') {
790
+ if (CLI_ARG_STRING_REGEX.test(value)) {
791
+ // if it matches the regex we treat it like a string
792
+ flags[normalizedArg] = value;
793
+ }
794
+ else {
795
+ const parsed = Number(value);
796
+ if (isNaN(parsed)) {
797
+ // parsing didn't go so well, we gotta get out of here
798
+ // this is unlikely given our regex guard above
799
+ // but hey, this is ultimately JS so let's be safe
800
+ throwNumberParsingError(rawArg, value);
801
+ }
802
+ else {
803
+ flags[normalizedArg] = parsed;
804
+ }
805
+ }
806
+ flags.knownArgs.push(rawArg);
807
+ flags.knownArgs.push(value);
808
+ }
809
+ else {
810
+ throwCLIParsingError(rawArg, 'expected a string or a number but received nothing');
811
+ }
812
+ }
813
+ // We're setting the log level, which can only be a set of specific string values
814
+ else if (readOnlyArrayHasStringMember(LOG_LEVEL_CLI_FLAGS, normalizedArg)) {
815
+ if (typeof value === 'string') {
816
+ if (isLogLevel(value)) {
817
+ flags[normalizedArg] = value;
818
+ flags.knownArgs.push(rawArg);
819
+ flags.knownArgs.push(value);
820
+ }
821
+ else {
822
+ throwCLIParsingError(rawArg, `expected to receive a valid log level but received "${String(value)}"`);
823
+ }
824
+ }
825
+ else {
826
+ throwCLIParsingError(rawArg, 'expected to receive a valid log level but received nothing');
678
827
  }
679
- flags.knownArgs.push(matchingArg);
680
- flags.knownArgs.push(value);
681
828
  }
682
829
  };
683
830
  /**
@@ -698,73 +845,34 @@ const parseStringNumberArg = (flags, args, configCaseName) => {
698
845
  * to a number.
699
846
  */
700
847
  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
- // our argument was passed at the command-line in the format --argName=arg-value
750
- [matchingArg, value] = parseEqualsArg(arg);
848
+ const Empty = Symbol('Empty');
849
+ /**
850
+ * A little helper which tries to parse a CLI value (as opposed to a flag) off
851
+ * of the argument array.
852
+ *
853
+ * We support a variety of different argument formats, but all of them start
854
+ * with `-`, so we can check the first character to test whether the next token
855
+ * in our array of CLI arguments is a flag name or a value.
856
+ *
857
+ * @param args an array of CLI args
858
+ * @returns either a string result or an Empty sentinel
859
+ */
860
+ const parseCLIValue = (args) => {
861
+ // it's possible the arguments array is empty, if so, return empty
862
+ if (args[0] === undefined) {
863
+ return Empty;
864
+ }
865
+ // all we're concerned with here is that it does not start with `"-"`,
866
+ // which would indicate it should be parsed as a CLI flag and not a value.
867
+ if (!args[0].startsWith('-')) {
868
+ // It's not a flag, so we return the value and defer any specific parsing
869
+ // until later on.
870
+ const value = args.shift();
871
+ if (typeof value === 'string') {
872
+ return value;
751
873
  }
752
- else if (arg === `--${dashCaseName}` || arg === `--${configCaseName}`) {
753
- // the next value in the array is assumed to be a value for this argument
754
- value = args[i + 1];
755
- matchingArg = arg;
756
- }
757
- else if (alias) {
758
- if (arg.startsWith(`-${alias}=`)) {
759
- [matchingArg, value] = parseEqualsArg(arg);
760
- }
761
- else if (arg === `-${alias}`) {
762
- value = args[i + 1];
763
- matchingArg = arg;
764
- }
765
- }
766
- });
767
- return { value, matchingArg };
874
+ }
875
+ return Empty;
768
876
  };
769
877
  /**
770
878
  * Parse an 'equals' argument, which is a CLI argument-value pair in the
@@ -800,8 +908,9 @@ const getValue = (args, configCaseName) => {
800
908
  * @returns a tuple containing the arg name and the value (if present)
801
909
  */
802
910
  const parseEqualsArg = (arg) => {
803
- const [originalArg, ...value] = arg.split('=');
804
- return [originalArg, value.join('=')];
911
+ const [originalArg, ...splitSections] = arg.split('=');
912
+ const value = splitSections.join('=');
913
+ return [originalArg, value === '' ? Empty : value];
805
914
  };
806
915
  /**
807
916
  * Small helper for getting type-system-level assurance that a `string` can be
@@ -811,11 +920,50 @@ const parseEqualsArg = (arg) => {
811
920
  * @returns whether this is a `LogLevel`
812
921
  */
813
922
  const isLogLevel = (maybeLogLevel) => readOnlyArrayHasStringMember(LOG_LEVELS, maybeLogLevel);
923
+ /**
924
+ * A little helper for constructing and throwing an error message with info
925
+ * about what went wrong
926
+ *
927
+ * @param flag the flag which encountered the error
928
+ * @param message a message specific to the error which was encountered
929
+ */
930
+ const throwCLIParsingError = (flag, message) => {
931
+ throw new Error(`when parsing CLI flag "${flag}": ${message}`);
932
+ };
933
+ /**
934
+ * Throw a specific error for the situation where we ran into an issue parsing
935
+ * a number.
936
+ *
937
+ * @param flag the flag for which we encountered the issue
938
+ * @param value what we were trying to parse
939
+ */
940
+ const throwNumberParsingError = (flag, value) => {
941
+ throwCLIParsingError(flag, `expected a number but received "${value}"`);
942
+ };
943
+ /**
944
+ * A little helper to 'dereference' a flag alias, which if you squint a little
945
+ * you can think of like a pointer to a full flag name. Thus 'c' is like a
946
+ * pointer to 'config', so here we're doing something like `*c`. Of course, this
947
+ * being JS, this is just a metaphor!
948
+ *
949
+ * If no 'dereference' is found for the possible alias we just return the
950
+ * passed string unmodified.
951
+ *
952
+ * @param maybeAlias a string which _could_ be an alias to a full flag name
953
+ * @returns the full aliased flag name, if found, or the passed string if not
954
+ */
955
+ const dereferenceAlias = (maybeAlias) => {
956
+ const possibleDereference = CLI_FLAG_ALIASES[maybeAlias];
957
+ if (typeof possibleDereference === 'string') {
958
+ return possibleDereference;
959
+ }
960
+ return maybeAlias;
961
+ };
814
962
 
815
963
  const dependencies = [
816
964
  {
817
965
  name: "@stencil/core",
818
- version: "2.19.2",
966
+ version: "3.0.0-alpha.0",
819
967
  main: "compiler/stencil.js",
820
968
  resources: [
821
969
  "package.json",
@@ -1562,7 +1710,16 @@ const CONFIG_PROPS_TO_ANONYMIZE = [
1562
1710
  // Props we delete entirely from the config for telemetry
1563
1711
  //
1564
1712
  // TODO(STENCIL-469): Investigate improving anonymization for tsCompilerOptions and devServer
1565
- const CONFIG_PROPS_TO_DELETE = ['sys', 'logger', 'tsCompilerOptions', 'devServer'];
1713
+ const CONFIG_PROPS_TO_DELETE = [
1714
+ 'commonjs',
1715
+ 'devServer',
1716
+ 'env',
1717
+ 'logger',
1718
+ 'rollupConfig',
1719
+ 'sys',
1720
+ 'testing',
1721
+ 'tsCompilerOptions',
1722
+ ];
1566
1723
  /**
1567
1724
  * Anonymize the config for telemetry, replacing potentially revealing config props
1568
1725
  * with a placeholder string if they are present (this lets us still track how frequently
@@ -1873,13 +2030,24 @@ const taskGenerate = async (coreCompiler, config) => {
1873
2030
  const { prompt } = await import('../sys/node/prompts.js');
1874
2031
  const input = config.flags.unknownArgs.find((arg) => !arg.startsWith('-')) ||
1875
2032
  (await prompt({ name: 'tagName', type: 'text', message: 'Component tag name (dash-case):' })).tagName;
2033
+ if (undefined === input) {
2034
+ // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
2035
+ // explicitly return here to avoid printing the error message.
2036
+ return;
2037
+ }
1876
2038
  const { dir, base: componentName } = path.parse(input);
1877
2039
  const tagError = validateComponentTag(componentName);
1878
2040
  if (tagError) {
1879
2041
  config.logger.error(tagError);
1880
2042
  return config.sys.exit(1);
1881
2043
  }
1882
- const extensionsToGenerate = ['tsx', ...(await chooseFilesToGenerate())];
2044
+ const filesToGenerateExt = await chooseFilesToGenerate();
2045
+ if (undefined === filesToGenerateExt) {
2046
+ // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
2047
+ // explicitly return here to avoid printing the error message.
2048
+ return;
2049
+ }
2050
+ const extensionsToGenerate = ['tsx', ...filesToGenerateExt];
1883
2051
  const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';
1884
2052
  const outDir = path.join(absoluteSrcDir, 'components', dir, componentName);
1885
2053
  await config.sys.createDir(path.join(outDir, testFolder), { recursive: true });