@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.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Stencil CLI (CommonJS) v2.19.2 | MIT Licensed | https://stenciljs.com
2
+ Stencil CLI (CommonJS) v3.0.0-alpha.0 | MIT Licensed | https://stenciljs.com
3
3
  */
4
4
  'use strict';
5
5
 
@@ -25,18 +25,6 @@ function _interopNamespace(e) {
25
25
  return Object.freeze(n);
26
26
  }
27
27
 
28
- /**
29
- * Convert a string from PascalCase to dash-case
30
- *
31
- * @param str the string to convert
32
- * @returns a converted string
33
- */
34
- const toDashCase = (str) => str
35
- .replace(/([A-Z0-9])/g, (match) => ` ${match[0]}`)
36
- .trim()
37
- .split(' ')
38
- .join('-')
39
- .toLowerCase();
40
28
  /**
41
29
  * Convert a string from dash-case / kebab-case to PascalCase (or CamelCase,
42
30
  * or whatever you call it!)
@@ -49,6 +37,16 @@ const dashToPascalCase = (str) => str
49
37
  .split('-')
50
38
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
51
39
  .join('');
40
+ /**
41
+ * Convert a string to 'camelCase'
42
+ *
43
+ * @param str the string to convert
44
+ * @returns the converted string
45
+ */
46
+ const toCamelCase = (str) => {
47
+ const pascalCase = dashToPascalCase(str);
48
+ return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
49
+ };
52
50
  const isFunction = (v) => typeof v === 'function';
53
51
  const isString = (v) => typeof v === 'string';
54
52
 
@@ -360,7 +358,7 @@ const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
360
358
  /**
361
359
  * All the Boolean options supported by the Stencil CLI
362
360
  */
363
- const BOOLEAN_CLI_ARGS = [
361
+ const BOOLEAN_CLI_FLAGS = [
364
362
  'build',
365
363
  'cache',
366
364
  'checkVersion',
@@ -443,7 +441,7 @@ const BOOLEAN_CLI_ARGS = [
443
441
  /**
444
442
  * All the Number options supported by the Stencil CLI
445
443
  */
446
- const NUMBER_CLI_ARGS = [
444
+ const NUMBER_CLI_FLAGS = [
447
445
  'port',
448
446
  // JEST CLI ARGS
449
447
  'maxConcurrency',
@@ -452,7 +450,7 @@ const NUMBER_CLI_ARGS = [
452
450
  /**
453
451
  * All the String options supported by the Stencil CLI
454
452
  */
455
- const STRING_CLI_ARGS = [
453
+ const STRING_CLI_FLAGS = [
456
454
  'address',
457
455
  'config',
458
456
  'docsApi',
@@ -491,7 +489,8 @@ const STRING_CLI_ARGS = [
491
489
  'testURL',
492
490
  'timers',
493
491
  'transform',
494
- // ARRAY ARGS
492
+ ];
493
+ const STRING_ARRAY_CLI_FLAGS = [
495
494
  'collectCoverageOnlyFrom',
496
495
  'coveragePathIgnorePatterns',
497
496
  'coverageReporters',
@@ -520,7 +519,7 @@ const STRING_CLI_ARGS = [
520
519
  * `maxWorkers` is an argument which is used both by Stencil _and_ by Jest,
521
520
  * which means that we need to support parsing both string and number values.
522
521
  */
523
- const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
522
+ const STRING_NUMBER_CLI_FLAGS = ['maxWorkers'];
524
523
  /**
525
524
  * All the LogLevel-type options supported by the Stencil CLI
526
525
  *
@@ -528,16 +527,21 @@ const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
528
527
  * but this approach lets us make sure that we're handling all
529
528
  * our arguments in a type-safe way.
530
529
  */
531
- const LOG_LEVEL_CLI_ARGS = ['logLevel'];
530
+ const LOG_LEVEL_CLI_FLAGS = ['logLevel'];
532
531
  /**
533
532
  * For a small subset of CLI options we support a short alias e.g. `'h'` for `'help'`
534
533
  */
535
- const CLI_ARG_ALIASES = {
536
- config: 'c',
537
- help: 'h',
538
- port: 'p',
539
- version: 'v',
534
+ const CLI_FLAG_ALIASES = {
535
+ c: 'config',
536
+ h: 'help',
537
+ p: 'port',
538
+ v: 'version',
540
539
  };
540
+ /**
541
+ * A regular expression which can be used to match a CLI flag for one of our
542
+ * short aliases.
543
+ */
544
+ const CLI_FLAG_REGEX = new RegExp(`^-[chpv]{1}$`);
541
545
  /**
542
546
  * Helper function for initializing a `ConfigFlags` object. Provide any overrides
543
547
  * for default values and off you go!
@@ -560,18 +564,22 @@ const createConfigFlags = (init = {}) => {
560
564
  * Parse command line arguments into a structured `ConfigFlags` object
561
565
  *
562
566
  * @param args an array of CLI flags
563
- * @param _sys an optional compiler system
564
567
  * @returns a structured ConfigFlags object
565
568
  */
566
- const parseFlags = (args, _sys) => {
567
- // TODO(STENCIL-509): remove the _sys parameter here ^^ (for v3)
569
+ const parseFlags = (args) => {
568
570
  const flags = createConfigFlags();
569
571
  // cmd line has more priority over npm scripts cmd
570
572
  flags.args = Array.isArray(args) ? args.slice() : [];
571
573
  if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
572
574
  flags.task = flags.args[0];
575
+ // if the first argument was a "task" (like `build`, `test`, etc) then
576
+ // we go on to parse the _rest_ of the CLI args
577
+ parseArgs(flags, args.slice(1));
578
+ }
579
+ else {
580
+ // we didn't find a leading flag, so we should just parse them all
581
+ parseArgs(flags, flags.args);
573
582
  }
574
- parseArgs(flags, flags.args);
575
583
  if (flags.task != null) {
576
584
  const i = flags.args.indexOf(flags.task);
577
585
  if (i > -1) {
@@ -588,120 +596,259 @@ const parseFlags = (args, _sys) => {
588
596
  return flags;
589
597
  };
590
598
  /**
591
- * Parse command line arguments that are enumerated in the `config-flags`
592
- * module. Handles leading dashes on arguments, aliases that are defined for a
593
- * small number of arguments, and parsing values for non-boolean arguments
594
- * (e.g. port number for the dev server).
599
+ * Parse the supported command line flags which are enumerated in the
600
+ * `config-flags` module. Handles leading dashes on arguments, aliases that are
601
+ * defined for a small number of arguments, and parsing values for non-boolean
602
+ * arguments (e.g. port number for the dev server).
603
+ *
604
+ * This parses the following grammar:
605
+ *
606
+ * CLIArguments → ""
607
+ * | CLITerm ( " " CLITerm )* ;
608
+ * CLITerm → EqualsArg
609
+ * | AliasEqualsArg
610
+ * | AliasArg
611
+ * | NegativeDashArg
612
+ * | NegativeArg
613
+ * | SimpleArg ;
614
+ * EqualsArg → "--" ArgName "=" CLIValue ;
615
+ * AliasEqualsArg → "-" AliasName "=" CLIValue ;
616
+ * AliasArg → "-" AliasName ( " " CLIValue )? ;
617
+ * NegativeDashArg → "--no-" ArgName ;
618
+ * NegativeArg → "--no" ArgName ;
619
+ * SimpleArg → "--" ArgName ( " " CLIValue )? ;
620
+ * ArgName → /^[a-zA-Z-]+$/ ;
621
+ * AliasName → /^[a-z]{1}$/ ;
622
+ * CLIValue → '"' /^[a-zA-Z0-9]+$/ '"'
623
+ * | /^[a-zA-Z0-9]+$/ ;
624
+ *
625
+ * There are additional constraints (not shown in the grammar for brevity's sake)
626
+ * on the type of `CLIValue` which will be associated with a particular argument.
627
+ * We enforce this by declaring lists of boolean, string, etc arguments and
628
+ * checking the types of values before setting them.
629
+ *
630
+ * We don't need to turn the list of CLI arg tokens into any kind of
631
+ * intermediate representation since we aren't concerned with doing anything
632
+ * other than setting the correct values on our ConfigFlags object. So we just
633
+ * parse the array of string arguments using a recursive-descent approach
634
+ * (which is not very deep since our grammar is pretty simple) and make the
635
+ * modifications we need to make to the {@link ConfigFlags} object as we go.
595
636
  *
596
637
  * @param flags a ConfigFlags object to which parsed arguments will be added
597
638
  * @param args an array of command-line arguments to parse
598
639
  */
599
640
  const parseArgs = (flags, args) => {
600
- BOOLEAN_CLI_ARGS.forEach((argName) => parseBooleanArg(flags, args, argName));
601
- STRING_CLI_ARGS.forEach((argName) => parseStringArg(flags, args, argName));
602
- NUMBER_CLI_ARGS.forEach((argName) => parseNumberArg(flags, args, argName));
603
- STRING_NUMBER_CLI_ARGS.forEach((argName) => parseStringNumberArg(flags, args, argName));
604
- LOG_LEVEL_CLI_ARGS.forEach((argName) => parseLogLevelArg(flags, args, argName));
641
+ const argsCopy = args.concat();
642
+ while (argsCopy.length > 0) {
643
+ // there are still unprocessed args to deal with
644
+ parseCLITerm(flags, argsCopy);
645
+ }
605
646
  };
606
647
  /**
607
- * Parse a boolean CLI argument. For these, we support the following formats:
608
- *
609
- * - `--booleanArg`
610
- * - `--boolean-arg`
611
- * - `--noBooleanArg`
612
- * - `--no-boolean-arg`
613
- *
614
- * The final two variants should be parsed to a value of `false` on the config
615
- * object.
648
+ * Given an array of CLI arguments, parse it and perform a series of side
649
+ * effects (setting values on the provided `ConfigFlags` object).
616
650
  *
617
- * @param flags the config flags object, while we'll modify
618
- * @param args our CLI arguments
619
- * @param configCaseName the argument we want to look at right now
651
+ * @param flags a {@link ConfigFlags} object which is updated as we parse the CLI
652
+ * arguments
653
+ * @param args a list of args to work through. This function (and some functions
654
+ * it calls) calls `Array.prototype.shift` to get the next argument to look at,
655
+ * so this parameter will be modified.
620
656
  */
621
- const parseBooleanArg = (flags, args, configCaseName) => {
622
- // we support both dash-case and PascalCase versions of the parameter
623
- // argName is 'configCase' version which can be found in BOOLEAN_ARG_OPTS
624
- const alias = CLI_ARG_ALIASES[configCaseName];
625
- const dashCaseName = toDashCase(configCaseName);
626
- if (typeof flags[configCaseName] !== 'boolean') {
627
- flags[configCaseName] = null;
628
- }
629
- args.forEach((cmdArg) => {
630
- let value;
631
- if (cmdArg === `--${configCaseName}` || cmdArg === `--${dashCaseName}`) {
632
- value = true;
633
- }
634
- else if (cmdArg === `--no-${dashCaseName}` || cmdArg === `--no${dashToPascalCase(dashCaseName)}`) {
635
- value = false;
636
- }
637
- else if (alias && cmdArg === `-${alias}`) {
638
- value = true;
639
- }
640
- if (value !== undefined && cmdArg !== undefined) {
641
- flags[configCaseName] = value;
642
- flags.knownArgs.push(cmdArg);
643
- }
644
- });
657
+ const parseCLITerm = (flags, args) => {
658
+ // pull off the first arg from the argument array
659
+ const arg = args.shift();
660
+ // array is empty, we're done!
661
+ if (arg === undefined)
662
+ return;
663
+ // EqualsArg → "--" ArgName "=" CLIValue ;
664
+ if (arg.startsWith('--') && arg.includes('=')) {
665
+ // we're dealing with an EqualsArg, we have a special helper for that
666
+ const [originalArg, value] = parseEqualsArg(arg);
667
+ setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);
668
+ }
669
+ // AliasEqualsArg → "-" AliasName "=" CLIValue ;
670
+ else if (arg.startsWith('-') && arg.includes('=')) {
671
+ // we're dealing with an AliasEqualsArg, we have a special helper for that
672
+ const [originalArg, value] = parseEqualsArg(arg);
673
+ setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);
674
+ }
675
+ // AliasArg → "-" AliasName ( " " CLIValue )? ;
676
+ else if (CLI_FLAG_REGEX.test(arg)) {
677
+ // this is a short alias, like `-c` for Config
678
+ setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));
679
+ }
680
+ // NegativeDashArg → "--no-" ArgName ;
681
+ else if (arg.startsWith('--no-') && arg.length > '--no-'.length) {
682
+ // this is a `NegativeDashArg` term, so we need to normalize the negative
683
+ // flag name and then set an appropriate value
684
+ const normalized = normalizeNegativeFlagName(arg);
685
+ setCLIArg(flags, arg, normalized, '');
686
+ }
687
+ // NegativeArg → "--no" ArgName ;
688
+ else if (arg.startsWith('--no') &&
689
+ !readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeFlagName(arg)) &&
690
+ readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeNegativeFlagName(arg))) {
691
+ // possibly dealing with a `NegativeArg` here. There is a little ambiguity
692
+ // here because we have arguments that already begin with `no` like
693
+ // `notify`, so we need to test if a normalized form of the raw argument is
694
+ // a valid and supported boolean flag.
695
+ setCLIArg(flags, arg, normalizeNegativeFlagName(arg), '');
696
+ }
697
+ // SimpleArg → "--" ArgName ( " " CLIValue )? ;
698
+ else if (arg.startsWith('--') && arg.length > '--'.length) {
699
+ setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));
700
+ }
701
+ // if we get here it is not an argument in our list of supported arguments.
702
+ // This doesn't necessarily mean we want to report an error or anything
703
+ // though! Instead, with unknown / unrecognized arguments we stick them into
704
+ // the `unknownArgs` array, which is used when we pass CLI args to Jest, for
705
+ // instance. So we just return void here.
645
706
  };
646
707
  /**
647
- * Parse a string CLI argument
708
+ * Normalize a 'negative' flag name, just to do a little pre-processing before
709
+ * we pass it to `setCLIArg`.
648
710
  *
649
- * @param flags the config flags object, while we'll modify
650
- * @param args our CLI arguments
651
- * @param configCaseName the argument we want to look at right now
711
+ * @param flagName the flag name to normalize
712
+ * @returns a normalized flag name
652
713
  */
653
- const parseStringArg = (flags, args, configCaseName) => {
654
- if (typeof flags[configCaseName] !== 'string') {
655
- flags[configCaseName] = null;
656
- }
657
- const { value, matchingArg } = getValue(args, configCaseName);
658
- if (value !== undefined && matchingArg !== undefined) {
659
- flags[configCaseName] = value;
660
- flags.knownArgs.push(matchingArg);
661
- flags.knownArgs.push(value);
662
- }
714
+ const normalizeNegativeFlagName = (flagName) => {
715
+ const trimmed = flagName.replace(/^--no[-]?/, '');
716
+ return normalizeFlagName(trimmed.charAt(0).toLowerCase() + trimmed.slice(1));
663
717
  };
664
718
  /**
665
- * Parse a number CLI argument
719
+ * Normalize a flag name by:
720
+ *
721
+ * - replacing any leading dashes (`--foo` -> `foo`)
722
+ * - converting `dash-case` to camelCase (if necessary)
723
+ *
724
+ * Normalizing in this context basically means converting the various
725
+ * supported flag spelling variants to the variant defined in our lists of
726
+ * supported arguments (e.g. BOOLEAN_CLI_FLAGS, etc). So, for instance,
727
+ * `--log-level` should be converted to `logLevel`.
728
+ *
729
+ * @param flagName the flag name to normalize
730
+ * @returns a normalized flag name
666
731
  *
667
- * @param flags the config flags object, while we'll modify
668
- * @param args our CLI arguments
669
- * @param configCaseName the argument we want to look at right now
670
732
  */
671
- const parseNumberArg = (flags, args, configCaseName) => {
672
- if (typeof flags[configCaseName] !== 'number') {
673
- flags[configCaseName] = null;
674
- }
675
- const { value, matchingArg } = getValue(args, configCaseName);
676
- if (value !== undefined && matchingArg !== undefined) {
677
- flags[configCaseName] = parseInt(value, 10);
678
- flags.knownArgs.push(matchingArg);
679
- flags.knownArgs.push(value);
680
- }
733
+ const normalizeFlagName = (flagName) => {
734
+ const trimmed = flagName.replace(/^-+/, '');
735
+ return trimmed.includes('-') ? toCamelCase(trimmed) : trimmed;
681
736
  };
682
737
  /**
683
- * Parse a CLI argument which may be either a string or a number
684
- *
685
- * @param flags the config flags object, while we'll modify
686
- * @param args our CLI arguments
687
- * @param configCaseName the argument we want to look at right now
688
- */
689
- const parseStringNumberArg = (flags, args, configCaseName) => {
690
- if (!['number', 'string'].includes(typeof flags[configCaseName])) {
691
- flags[configCaseName] = null;
738
+ * Set a value on a provided {@link ConfigFlags} object, given an argument
739
+ * name and a raw string value. This function dispatches to other functions
740
+ * which make sure that the string value can be properly parsed into a JS
741
+ * runtime value of the right type (e.g. number, string, etc).
742
+ *
743
+ * @throws if a value cannot be parsed to the right type for a given flag
744
+ * @param flags a {@link ConfigFlags} object
745
+ * @param rawArg the raw argument name matched by the parser
746
+ * @param normalizedArg an argument with leading control characters (`--`,
747
+ * `--no-`, etc) removed
748
+ * @param value the raw value to be set onto the config flags object
749
+ */
750
+ const setCLIArg = (flags, rawArg, normalizedArg, value) => {
751
+ normalizedArg = dereferenceAlias(normalizedArg);
752
+ // We're setting a boolean!
753
+ if (readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizedArg)) {
754
+ flags[normalizedArg] =
755
+ typeof value === 'string'
756
+ ? Boolean(value)
757
+ : // no value was supplied, default to true
758
+ true;
759
+ flags.knownArgs.push(rawArg);
760
+ }
761
+ // We're setting a string!
762
+ else if (readOnlyArrayHasStringMember(STRING_CLI_FLAGS, normalizedArg)) {
763
+ if (typeof value === 'string') {
764
+ flags[normalizedArg] = value;
765
+ flags.knownArgs.push(rawArg);
766
+ flags.knownArgs.push(value);
767
+ }
768
+ else {
769
+ throwCLIParsingError(rawArg, 'expected a string argument but received nothing');
770
+ }
771
+ }
772
+ // We're setting a string, but it's one where the user can pass multiple values,
773
+ // like `--reporters="default" --reporters="jest-junit"`
774
+ else if (readOnlyArrayHasStringMember(STRING_ARRAY_CLI_FLAGS, normalizedArg)) {
775
+ if (typeof value === 'string') {
776
+ if (!Array.isArray(flags[normalizedArg])) {
777
+ flags[normalizedArg] = [];
778
+ }
779
+ const targetArray = flags[normalizedArg];
780
+ // this is irritating, but TS doesn't know that the `!Array.isArray`
781
+ // check above guarantees we have an array to work with here, and it
782
+ // doesn't want to narrow the type of `flags[normalizedArg]`, so we need
783
+ // to grab a reference to that array and then `Array.isArray` that. Bah!
784
+ if (Array.isArray(targetArray)) {
785
+ targetArray.push(value);
786
+ flags.knownArgs.push(rawArg);
787
+ flags.knownArgs.push(value);
788
+ }
789
+ }
790
+ else {
791
+ throwCLIParsingError(rawArg, 'expected a string argument but received nothing');
792
+ }
692
793
  }
693
- const { value, matchingArg } = getValue(args, configCaseName);
694
- if (value !== undefined && matchingArg !== undefined) {
695
- if (CLI_ARG_STRING_REGEX.test(value)) {
696
- // if it matches the regex we treat it like a string
697
- flags[configCaseName] = value;
794
+ // We're setting a number!
795
+ else if (readOnlyArrayHasStringMember(NUMBER_CLI_FLAGS, normalizedArg)) {
796
+ if (typeof value === 'string') {
797
+ const parsed = parseInt(value, 10);
798
+ if (isNaN(parsed)) {
799
+ throwNumberParsingError(rawArg, value);
800
+ }
801
+ else {
802
+ flags[normalizedArg] = parsed;
803
+ flags.knownArgs.push(rawArg);
804
+ flags.knownArgs.push(value);
805
+ }
698
806
  }
699
807
  else {
700
- // it was a number, great!
701
- flags[configCaseName] = Number(value);
808
+ throwCLIParsingError(rawArg, 'expected a number argument but received nothing');
809
+ }
810
+ }
811
+ // We're setting a value which could be either a string _or_ a number
812
+ else if (readOnlyArrayHasStringMember(STRING_NUMBER_CLI_FLAGS, normalizedArg)) {
813
+ if (typeof value === 'string') {
814
+ if (CLI_ARG_STRING_REGEX.test(value)) {
815
+ // if it matches the regex we treat it like a string
816
+ flags[normalizedArg] = value;
817
+ }
818
+ else {
819
+ const parsed = Number(value);
820
+ if (isNaN(parsed)) {
821
+ // parsing didn't go so well, we gotta get out of here
822
+ // this is unlikely given our regex guard above
823
+ // but hey, this is ultimately JS so let's be safe
824
+ throwNumberParsingError(rawArg, value);
825
+ }
826
+ else {
827
+ flags[normalizedArg] = parsed;
828
+ }
829
+ }
830
+ flags.knownArgs.push(rawArg);
831
+ flags.knownArgs.push(value);
832
+ }
833
+ else {
834
+ throwCLIParsingError(rawArg, 'expected a string or a number but received nothing');
835
+ }
836
+ }
837
+ // We're setting the log level, which can only be a set of specific string values
838
+ else if (readOnlyArrayHasStringMember(LOG_LEVEL_CLI_FLAGS, normalizedArg)) {
839
+ if (typeof value === 'string') {
840
+ if (isLogLevel(value)) {
841
+ flags[normalizedArg] = value;
842
+ flags.knownArgs.push(rawArg);
843
+ flags.knownArgs.push(value);
844
+ }
845
+ else {
846
+ throwCLIParsingError(rawArg, `expected to receive a valid log level but received "${String(value)}"`);
847
+ }
848
+ }
849
+ else {
850
+ throwCLIParsingError(rawArg, 'expected to receive a valid log level but received nothing');
702
851
  }
703
- flags.knownArgs.push(matchingArg);
704
- flags.knownArgs.push(value);
705
852
  }
706
853
  };
707
854
  /**
@@ -722,73 +869,34 @@ const parseStringNumberArg = (flags, args, configCaseName) => {
722
869
  * to a number.
723
870
  */
724
871
  const CLI_ARG_STRING_REGEX = /[^\d\.Ee\+\-]+/g;
725
- /**
726
- * Parse a LogLevel CLI argument. These can be only a specific
727
- * set of strings, so this function takes care of validating that
728
- * the value is correct.
729
- *
730
- * @param flags the config flags object, while we'll modify
731
- * @param args our CLI arguments
732
- * @param configCaseName the argument we want to look at right now
733
- */
734
- const parseLogLevelArg = (flags, args, configCaseName) => {
735
- if (typeof flags[configCaseName] !== 'string') {
736
- flags[configCaseName] = null;
737
- }
738
- const { value, matchingArg } = getValue(args, configCaseName);
739
- if (value !== undefined && matchingArg !== undefined && isLogLevel(value)) {
740
- flags[configCaseName] = value;
741
- flags.knownArgs.push(matchingArg);
742
- flags.knownArgs.push(value);
743
- }
744
- };
745
- /**
746
- * Helper for pulling values out from the raw array of CLI arguments. This logic
747
- * is shared between a few different types of CLI args.
748
- *
749
- * We look for arguments in the following formats:
750
- *
751
- * - `--my-cli-argument value`
752
- * - `--my-cli-argument=value`
753
- * - `--myCliArgument value`
754
- * - `--myCliArgument=value`
755
- *
756
- * We also check for shortened aliases, which we define for a few arguments.
757
- *
758
- * @param args the CLI args we're dealing with
759
- * @param configCaseName the ConfigFlag key which we're looking to pull out a value for
760
- * @returns the value for the flag as well as the exact string which it matched from
761
- * the user input.
762
- */
763
- const getValue = (args, configCaseName) => {
764
- // for some CLI args we have a short alias, like 'c' for 'config'
765
- const alias = CLI_ARG_ALIASES[configCaseName];
766
- // we support supplying arguments in both dash-case and configCase
767
- // for ease of use
768
- const dashCaseName = toDashCase(configCaseName);
769
- let value;
770
- let matchingArg;
771
- args.forEach((arg, i) => {
772
- if (arg.startsWith(`--${dashCaseName}=`) || arg.startsWith(`--${configCaseName}=`)) {
773
- // our argument was passed at the command-line in the format --argName=arg-value
774
- [matchingArg, value] = parseEqualsArg(arg);
872
+ const Empty = Symbol('Empty');
873
+ /**
874
+ * A little helper which tries to parse a CLI value (as opposed to a flag) off
875
+ * of the argument array.
876
+ *
877
+ * We support a variety of different argument formats, but all of them start
878
+ * with `-`, so we can check the first character to test whether the next token
879
+ * in our array of CLI arguments is a flag name or a value.
880
+ *
881
+ * @param args an array of CLI args
882
+ * @returns either a string result or an Empty sentinel
883
+ */
884
+ const parseCLIValue = (args) => {
885
+ // it's possible the arguments array is empty, if so, return empty
886
+ if (args[0] === undefined) {
887
+ return Empty;
888
+ }
889
+ // all we're concerned with here is that it does not start with `"-"`,
890
+ // which would indicate it should be parsed as a CLI flag and not a value.
891
+ if (!args[0].startsWith('-')) {
892
+ // It's not a flag, so we return the value and defer any specific parsing
893
+ // until later on.
894
+ const value = args.shift();
895
+ if (typeof value === 'string') {
896
+ return value;
775
897
  }
776
- else if (arg === `--${dashCaseName}` || arg === `--${configCaseName}`) {
777
- // the next value in the array is assumed to be a value for this argument
778
- value = args[i + 1];
779
- matchingArg = arg;
780
- }
781
- else if (alias) {
782
- if (arg.startsWith(`-${alias}=`)) {
783
- [matchingArg, value] = parseEqualsArg(arg);
784
- }
785
- else if (arg === `-${alias}`) {
786
- value = args[i + 1];
787
- matchingArg = arg;
788
- }
789
- }
790
- });
791
- return { value, matchingArg };
898
+ }
899
+ return Empty;
792
900
  };
793
901
  /**
794
902
  * Parse an 'equals' argument, which is a CLI argument-value pair in the
@@ -824,8 +932,9 @@ const getValue = (args, configCaseName) => {
824
932
  * @returns a tuple containing the arg name and the value (if present)
825
933
  */
826
934
  const parseEqualsArg = (arg) => {
827
- const [originalArg, ...value] = arg.split('=');
828
- return [originalArg, value.join('=')];
935
+ const [originalArg, ...splitSections] = arg.split('=');
936
+ const value = splitSections.join('=');
937
+ return [originalArg, value === '' ? Empty : value];
829
938
  };
830
939
  /**
831
940
  * Small helper for getting type-system-level assurance that a `string` can be
@@ -835,11 +944,50 @@ const parseEqualsArg = (arg) => {
835
944
  * @returns whether this is a `LogLevel`
836
945
  */
837
946
  const isLogLevel = (maybeLogLevel) => readOnlyArrayHasStringMember(LOG_LEVELS, maybeLogLevel);
947
+ /**
948
+ * A little helper for constructing and throwing an error message with info
949
+ * about what went wrong
950
+ *
951
+ * @param flag the flag which encountered the error
952
+ * @param message a message specific to the error which was encountered
953
+ */
954
+ const throwCLIParsingError = (flag, message) => {
955
+ throw new Error(`when parsing CLI flag "${flag}": ${message}`);
956
+ };
957
+ /**
958
+ * Throw a specific error for the situation where we ran into an issue parsing
959
+ * a number.
960
+ *
961
+ * @param flag the flag for which we encountered the issue
962
+ * @param value what we were trying to parse
963
+ */
964
+ const throwNumberParsingError = (flag, value) => {
965
+ throwCLIParsingError(flag, `expected a number but received "${value}"`);
966
+ };
967
+ /**
968
+ * A little helper to 'dereference' a flag alias, which if you squint a little
969
+ * you can think of like a pointer to a full flag name. Thus 'c' is like a
970
+ * pointer to 'config', so here we're doing something like `*c`. Of course, this
971
+ * being JS, this is just a metaphor!
972
+ *
973
+ * If no 'dereference' is found for the possible alias we just return the
974
+ * passed string unmodified.
975
+ *
976
+ * @param maybeAlias a string which _could_ be an alias to a full flag name
977
+ * @returns the full aliased flag name, if found, or the passed string if not
978
+ */
979
+ const dereferenceAlias = (maybeAlias) => {
980
+ const possibleDereference = CLI_FLAG_ALIASES[maybeAlias];
981
+ if (typeof possibleDereference === 'string') {
982
+ return possibleDereference;
983
+ }
984
+ return maybeAlias;
985
+ };
838
986
 
839
987
  const dependencies = [
840
988
  {
841
989
  name: "@stencil/core",
842
- version: "2.19.2",
990
+ version: "3.0.0-alpha.0",
843
991
  main: "compiler/stencil.js",
844
992
  resources: [
845
993
  "package.json",
@@ -1586,7 +1734,16 @@ const CONFIG_PROPS_TO_ANONYMIZE = [
1586
1734
  // Props we delete entirely from the config for telemetry
1587
1735
  //
1588
1736
  // TODO(STENCIL-469): Investigate improving anonymization for tsCompilerOptions and devServer
1589
- const CONFIG_PROPS_TO_DELETE = ['sys', 'logger', 'tsCompilerOptions', 'devServer'];
1737
+ const CONFIG_PROPS_TO_DELETE = [
1738
+ 'commonjs',
1739
+ 'devServer',
1740
+ 'env',
1741
+ 'logger',
1742
+ 'rollupConfig',
1743
+ 'sys',
1744
+ 'testing',
1745
+ 'tsCompilerOptions',
1746
+ ];
1590
1747
  /**
1591
1748
  * Anonymize the config for telemetry, replacing potentially revealing config props
1592
1749
  * with a placeholder string if they are present (this lets us still track how frequently
@@ -1897,13 +2054,24 @@ const taskGenerate = async (coreCompiler, config) => {
1897
2054
  const { prompt } = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('../sys/node/prompts.js')); });
1898
2055
  const input = config.flags.unknownArgs.find((arg) => !arg.startsWith('-')) ||
1899
2056
  (await prompt({ name: 'tagName', type: 'text', message: 'Component tag name (dash-case):' })).tagName;
2057
+ if (undefined === input) {
2058
+ // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
2059
+ // explicitly return here to avoid printing the error message.
2060
+ return;
2061
+ }
1900
2062
  const { dir, base: componentName } = path.parse(input);
1901
2063
  const tagError = validateComponentTag(componentName);
1902
2064
  if (tagError) {
1903
2065
  config.logger.error(tagError);
1904
2066
  return config.sys.exit(1);
1905
2067
  }
1906
- const extensionsToGenerate = ['tsx', ...(await chooseFilesToGenerate())];
2068
+ const filesToGenerateExt = await chooseFilesToGenerate();
2069
+ if (undefined === filesToGenerateExt) {
2070
+ // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
2071
+ // explicitly return here to avoid printing the error message.
2072
+ return;
2073
+ }
2074
+ const extensionsToGenerate = ['tsx', ...filesToGenerateExt];
1907
2075
  const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';
1908
2076
  const outDir = path.join(absoluteSrcDir, 'components', dir, componentName);
1909
2077
  await config.sys.createDir(path.join(outDir, testFolder), { recursive: true });