@rindo/core 2.17.4 → 2.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/cli/config-flags.d.ts +33 -21
  2. package/cli/index.cjs +693 -401
  3. package/cli/index.d.ts +3 -0
  4. package/cli/index.js +693 -401
  5. package/cli/package.json +1 -1
  6. package/compiler/lib.dom.d.ts +898 -184
  7. package/compiler/lib.dom.iterable.d.ts +22 -4
  8. package/compiler/lib.es2015.collection.d.ts +62 -1
  9. package/compiler/lib.es2015.core.d.ts +3 -3
  10. package/compiler/lib.es2015.iterable.d.ts +2 -1
  11. package/compiler/lib.es2015.promise.d.ts +9 -4
  12. package/compiler/lib.es2015.proxy.d.ts +91 -2
  13. package/compiler/lib.es2015.reflect.d.ts +26 -3
  14. package/compiler/lib.es2015.symbol.wellknown.d.ts +3 -3
  15. package/compiler/lib.es2017.intl.d.ts +16 -1
  16. package/compiler/lib.es2019.d.ts +1 -0
  17. package/compiler/lib.es2019.intl.d.ts +25 -0
  18. package/compiler/lib.es2020.bigint.d.ts +7 -5
  19. package/compiler/lib.es2020.d.ts +2 -0
  20. package/compiler/lib.es2020.date.d.ts +44 -0
  21. package/compiler/lib.es2020.intl.d.ts +81 -16
  22. package/compiler/lib.es2020.number.d.ts +30 -0
  23. package/compiler/lib.es2021.intl.d.ts +116 -6
  24. package/compiler/lib.es2022.array.d.ts +123 -0
  25. package/compiler/lib.es2022.d.ts +27 -0
  26. package/compiler/lib.es2022.error.d.ts +75 -0
  27. package/compiler/lib.es2022.full.d.ts +25 -0
  28. package/compiler/lib.es2022.intl.d.ts +111 -0
  29. package/compiler/lib.es2022.object.d.ts +28 -0
  30. package/compiler/lib.es2022.sharedmemory.d.ts +27 -0
  31. package/compiler/lib.es2022.string.d.ts +27 -0
  32. package/compiler/lib.es5.d.ts +62 -31
  33. package/compiler/lib.esnext.d.ts +1 -1
  34. package/compiler/lib.esnext.intl.d.ts +8 -1
  35. package/compiler/lib.webworker.d.ts +540 -81
  36. package/compiler/lib.webworker.iterable.d.ts +19 -4
  37. package/compiler/package.json +1 -1
  38. package/compiler/rindo.d.ts +3 -25
  39. package/compiler/rindo.js +54678 -52205
  40. package/compiler/rindo.min.js +2 -2
  41. package/compiler/sys/in-memory-fs.d.ts +218 -0
  42. package/compiler/transpile.d.ts +32 -0
  43. package/dependencies.json +12 -1
  44. package/dev-server/client/app-error.d.ts +1 -1
  45. package/dev-server/client/index.d.ts +2 -2
  46. package/dev-server/client/index.js +241 -241
  47. package/dev-server/client/package.json +1 -1
  48. package/dev-server/connector.html +3 -3
  49. package/dev-server/index.d.ts +1 -1
  50. package/dev-server/index.js +2 -2
  51. package/dev-server/open-in-editor-api.js +1 -1
  52. package/dev-server/package.json +1 -1
  53. package/dev-server/server-process.js +1192 -1158
  54. package/dev-server/ws.js +1 -1
  55. package/internal/app-data/package.json +1 -1
  56. package/internal/client/css-shim.js +2 -2
  57. package/internal/client/dom.js +1 -1
  58. package/internal/client/index.js +1130 -823
  59. package/internal/client/package.json +1 -1
  60. package/internal/client/patch-browser.js +19 -1
  61. package/internal/client/patch-esm.js +1 -1
  62. package/internal/client/polyfills/css-shim.js +1 -1
  63. package/internal/client/shadow-css.js +1 -1
  64. package/internal/hydrate/index.js +154 -143
  65. package/internal/hydrate/package.json +1 -1
  66. package/internal/hydrate/runner.d.ts +1 -1
  67. package/internal/hydrate/runner.js +106 -106
  68. package/internal/package.json +1 -1
  69. package/internal/rindo-core/index.d.ts +9 -10
  70. package/internal/rindo-private.d.ts +149 -184
  71. package/internal/rindo-public-compiler.d.ts +83 -38
  72. package/internal/rindo-public-docs.d.ts +24 -0
  73. package/internal/rindo-public-runtime.d.ts +79 -7
  74. package/internal/testing/index.js +187 -175
  75. package/internal/testing/package.json +1 -1
  76. package/mock-doc/index.cjs +526 -501
  77. package/mock-doc/index.d.ts +15 -14
  78. package/mock-doc/index.js +526 -501
  79. package/mock-doc/package.json +1 -1
  80. package/package.json +48 -59
  81. package/readme.md +44 -31
  82. package/screenshot/compare/build/p-f4745c2f.entry.js +1 -1
  83. package/screenshot/index.d.ts +1 -1
  84. package/screenshot/index.js +13 -13
  85. package/screenshot/package.json +1 -1
  86. package/screenshot/pixel-match.js +983 -849
  87. package/sys/node/autoprefixer.js +2 -2
  88. package/sys/node/glob.js +1 -1
  89. package/sys/node/index.d.ts +4 -0
  90. package/sys/node/index.js +399 -413
  91. package/sys/node/package.json +1 -1
  92. package/sys/node/prompts.js +1 -1
  93. package/sys/node/worker.js +1 -1
  94. package/testing/index.d.ts +6 -6
  95. package/testing/index.js +684 -839
  96. package/testing/jest/jest-config.d.ts +1 -1
  97. package/testing/jest/jest-preprocessor.d.ts +3 -3
  98. package/testing/jest/jest-serializer.d.ts +1 -2
  99. package/testing/matchers/index.d.ts +3 -3
  100. package/testing/mock-fetch.d.ts +1 -1
  101. package/testing/mocks.d.ts +2 -2
  102. package/testing/package.json +1 -1
  103. package/testing/puppeteer/puppeteer-declarations.d.ts +5 -5
  104. package/testing/puppeteer/puppeteer-element.d.ts +2 -2
  105. package/testing/puppeteer/puppeteer-events.d.ts +1 -1
  106. package/testing/testing-logger.d.ts +1 -1
  107. package/testing/testing-utils.d.ts +6 -5
  108. package/testing/testing.d.ts +1 -1
package/cli/index.js CHANGED
@@ -1,41 +1,6 @@
1
1
  /*!
2
- Rindo CLI v2.17.4 | MIT Licensed | https://rindojs.web.app
2
+ Rindo CLI v2.22.2 | MIT Licensed | https://rindojs.web.app
3
3
  */
4
- /**
5
- * This sets the log level hierarchy for our terminal logger, ranging from
6
- * most to least verbose.
7
- *
8
- * Ordering the levels like this lets us easily check whether we should log a
9
- * message at a given time. For instance, if the log level is set to `'warn'`,
10
- * then anything passed to the logger with level `'warn'` or `'error'` should
11
- * be logged, but we should _not_ log anything with level `'info'` or `'debug'`.
12
- *
13
- * If we have a current log level `currentLevel` and a message with level
14
- * `msgLevel` is passed to the logger, we can determine whether or not we should
15
- * log it by checking if the log level on the message is further up or at the
16
- * same level in the hierarchy than `currentLevel`, like so:
17
- *
18
- * ```ts
19
- * LOG_LEVELS.indexOf(msgLevel) >= LOG_LEVELS.indexOf(currentLevel)
20
- * ```
21
- *
22
- * NOTE: for the reasons described above, do not change the order of the entries
23
- * in this array without good reason!
24
- */
25
- const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
26
-
27
- /**
28
- * Convert a string from PascalCase to dash-case
29
- *
30
- * @param str the string to convert
31
- * @returns a converted string
32
- */
33
- const toDashCase = (str) => str
34
- .replace(/([A-Z0-9])/g, (match) => ` ${match[0]}`)
35
- .trim()
36
- .split(' ')
37
- .join('-')
38
- .toLowerCase();
39
4
  /**
40
5
  * Convert a string from dash-case / kebab-case to PascalCase (or CamelCase,
41
6
  * or whatever you call it!)
@@ -48,6 +13,16 @@ const dashToPascalCase = (str) => str
48
13
  .split('-')
49
14
  .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
50
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
+ };
51
26
  const isFunction = (v) => typeof v === 'function';
52
27
  const isString = (v) => typeof v === 'string';
53
28
 
@@ -199,18 +174,18 @@ const getEncodedRootLength = (path) => {
199
174
  return 0;
200
175
  const ch0 = path.charCodeAt(0);
201
176
  // POSIX or UNC
202
- if (ch0 === 47 /* slash */ || ch0 === 92 /* backslash */) {
177
+ if (ch0 === 47 /* CharacterCodes.slash */ || ch0 === 92 /* CharacterCodes.backslash */) {
203
178
  if (path.charCodeAt(1) !== ch0)
204
179
  return 1; // POSIX: "/" (or non-normalized "\")
205
- const p1 = path.indexOf(ch0 === 47 /* slash */ ? '/' : altDirectorySeparator, 2);
180
+ const p1 = path.indexOf(ch0 === 47 /* CharacterCodes.slash */ ? '/' : altDirectorySeparator, 2);
206
181
  if (p1 < 0)
207
182
  return path.length; // UNC: "//server" or "\\server"
208
183
  return p1 + 1; // UNC: "//server/" or "\\server\"
209
184
  }
210
185
  // DOS
211
- if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* colon */) {
186
+ if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* CharacterCodes.colon */) {
212
187
  const ch2 = path.charCodeAt(2);
213
- if (ch2 === 47 /* slash */ || ch2 === 92 /* backslash */)
188
+ if (ch2 === 47 /* CharacterCodes.slash */ || ch2 === 92 /* CharacterCodes.backslash */)
214
189
  return 3; // DOS: "c:/" or "c:\"
215
190
  if (path.length === 2)
216
191
  return 2; // DOS: "c:" (but not "c:d")
@@ -232,7 +207,7 @@ const getEncodedRootLength = (path) => {
232
207
  isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) {
233
208
  const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);
234
209
  if (volumeSeparatorEnd !== -1) {
235
- if (path.charCodeAt(volumeSeparatorEnd) === 47 /* slash */) {
210
+ if (path.charCodeAt(volumeSeparatorEnd) === 47 /* CharacterCodes.slash */) {
236
211
  // URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/"
237
212
  return ~(volumeSeparatorEnd + 1);
238
213
  }
@@ -250,15 +225,15 @@ const getEncodedRootLength = (path) => {
250
225
  // relative
251
226
  return 0;
252
227
  };
253
- const isVolumeCharacter = (charCode) => (charCode >= 97 /* a */ && charCode <= 122 /* z */) ||
254
- (charCode >= 65 /* A */ && charCode <= 90 /* Z */);
228
+ const isVolumeCharacter = (charCode) => (charCode >= 97 /* CharacterCodes.a */ && charCode <= 122 /* CharacterCodes.z */) ||
229
+ (charCode >= 65 /* CharacterCodes.A */ && charCode <= 90 /* CharacterCodes.Z */);
255
230
  const getFileUrlVolumeSeparatorEnd = (url, start) => {
256
231
  const ch0 = url.charCodeAt(start);
257
- if (ch0 === 58 /* colon */)
232
+ if (ch0 === 58 /* CharacterCodes.colon */)
258
233
  return start + 1;
259
- if (ch0 === 37 /* percent */ && url.charCodeAt(start + 1) === 51 /* _3 */) {
234
+ if (ch0 === 37 /* CharacterCodes.percent */ && url.charCodeAt(start + 1) === 51 /* CharacterCodes._3 */) {
260
235
  const ch2 = url.charCodeAt(start + 2);
261
- if (ch2 === 97 /* a */ || ch2 === 65 /* A */)
236
+ if (ch2 === 97 /* CharacterCodes.a */ || ch2 === 65 /* CharacterCodes.A */)
262
237
  return start + 3;
263
238
  }
264
239
  return -1;
@@ -273,6 +248,22 @@ const pathComponents = (path, rootLength) => {
273
248
  return [root, ...rest];
274
249
  };
275
250
 
251
+ /**
252
+ * Check whether a string is a member of a ReadonlyArray<string>
253
+ *
254
+ * We need a little helper for this because unfortunately `includes` is typed
255
+ * on `ReadonlyArray<T>` as `(el: T): boolean` so a `string` cannot be passed
256
+ * to `includes` on a `ReadonlyArray` 😢 thus we have a little helper function
257
+ * where we do the type coercion just once.
258
+ *
259
+ * see microsoft/TypeScript#31018 for some discussion of this
260
+ *
261
+ * @param readOnlyArray the array we're checking
262
+ * @param maybeMember a value which is possibly a member of the array
263
+ * @returns whether the array contains the member or not
264
+ */
265
+ const readOnlyArrayHasStringMember = (readOnlyArray, maybeMember) => readOnlyArray.includes(maybeMember);
266
+
276
267
  /**
277
268
  * Validates that a component tag meets required naming conventions to be used for a web component
278
269
  * @param tag the tag to validate
@@ -317,10 +308,33 @@ const validateComponentTag = (tag) => {
317
308
  return undefined;
318
309
  };
319
310
 
311
+ /**
312
+ * This sets the log level hierarchy for our terminal logger, ranging from
313
+ * most to least verbose.
314
+ *
315
+ * Ordering the levels like this lets us easily check whether we should log a
316
+ * message at a given time. For instance, if the log level is set to `'warn'`,
317
+ * then anything passed to the logger with level `'warn'` or `'error'` should
318
+ * be logged, but we should _not_ log anything with level `'info'` or `'debug'`.
319
+ *
320
+ * If we have a current log level `currentLevel` and a message with level
321
+ * `msgLevel` is passed to the logger, we can determine whether or not we should
322
+ * log it by checking if the log level on the message is further up or at the
323
+ * same level in the hierarchy than `currentLevel`, like so:
324
+ *
325
+ * ```ts
326
+ * LOG_LEVELS.indexOf(msgLevel) >= LOG_LEVELS.indexOf(currentLevel)
327
+ * ```
328
+ *
329
+ * NOTE: for the reasons described above, do not change the order of the entries
330
+ * in this array without good reason!
331
+ */
332
+ const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
333
+
320
334
  /**
321
335
  * All the Boolean options supported by the Rindo CLI
322
336
  */
323
- const BOOLEAN_CLI_ARGS = [
337
+ const BOOLEAN_CLI_FLAGS = [
324
338
  'build',
325
339
  'cache',
326
340
  'checkVersion',
@@ -403,7 +417,7 @@ const BOOLEAN_CLI_ARGS = [
403
417
  /**
404
418
  * All the Number options supported by the Rindo CLI
405
419
  */
406
- const NUMBER_CLI_ARGS = [
420
+ const NUMBER_CLI_FLAGS = [
407
421
  'port',
408
422
  // JEST CLI ARGS
409
423
  'maxConcurrency',
@@ -412,7 +426,7 @@ const NUMBER_CLI_ARGS = [
412
426
  /**
413
427
  * All the String options supported by the Rindo CLI
414
428
  */
415
- const STRING_CLI_ARGS = [
429
+ const STRING_CLI_FLAGS = [
416
430
  'address',
417
431
  'config',
418
432
  'docsApi',
@@ -451,7 +465,8 @@ const STRING_CLI_ARGS = [
451
465
  'testURL',
452
466
  'timers',
453
467
  'transform',
454
- // ARRAY ARGS
468
+ ];
469
+ const STRING_ARRAY_CLI_FLAGS = [
455
470
  'collectCoverageOnlyFrom',
456
471
  'coveragePathIgnorePatterns',
457
472
  'coverageReporters',
@@ -480,7 +495,7 @@ const STRING_CLI_ARGS = [
480
495
  * `maxWorkers` is an argument which is used both by Rindo _and_ by Jest,
481
496
  * which means that we need to support parsing both string and number values.
482
497
  */
483
- const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
498
+ const STRING_NUMBER_CLI_FLAGS = ['maxWorkers'];
484
499
  /**
485
500
  * All the LogLevel-type options supported by the Rindo CLI
486
501
  *
@@ -488,16 +503,21 @@ const STRING_NUMBER_CLI_ARGS = ['maxWorkers'];
488
503
  * but this approach lets us make sure that we're handling all
489
504
  * our arguments in a type-safe way.
490
505
  */
491
- const LOG_LEVEL_CLI_ARGS = ['logLevel'];
506
+ const LOG_LEVEL_CLI_FLAGS = ['logLevel'];
492
507
  /**
493
508
  * For a small subset of CLI options we support a short alias e.g. `'h'` for `'help'`
494
509
  */
495
- const CLI_ARG_ALIASES = {
496
- config: 'c',
497
- help: 'h',
498
- port: 'p',
499
- version: 'v',
510
+ const CLI_FLAG_ALIASES = {
511
+ c: 'config',
512
+ h: 'help',
513
+ p: 'port',
514
+ v: 'version',
500
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}$`);
501
521
  /**
502
522
  * Helper function for initializing a `ConfigFlags` object. Provide any overrides
503
523
  * for default values and off you go!
@@ -530,8 +550,14 @@ const parseFlags = (args, _sys) => {
530
550
  flags.args = Array.isArray(args) ? args.slice() : [];
531
551
  if (flags.args.length > 0 && flags.args[0] && !flags.args[0].startsWith('-')) {
532
552
  flags.task = flags.args[0];
553
+ // if the first argument was a "task" (like `build`, `test`, etc) then
554
+ // we go on to parse the _rest_ of the CLI args
555
+ parseArgs(flags, args.slice(1));
556
+ }
557
+ else {
558
+ // we didn't find a leading flag, so we should just parse them all
559
+ parseArgs(flags, flags.args);
533
560
  }
534
- parseArgs(flags, flags.args);
535
561
  if (flags.task != null) {
536
562
  const i = flags.args.indexOf(flags.task);
537
563
  if (i > -1) {
@@ -548,120 +574,259 @@ const parseFlags = (args, _sys) => {
548
574
  return flags;
549
575
  };
550
576
  /**
551
- * Parse command line arguments that are enumerated in the `config-flags`
552
- * module. Handles leading dashes on arguments, aliases that are defined for a
553
- * small number of arguments, and parsing values for non-boolean arguments
554
- * (e.g. port number for the dev server).
577
+ * Parse the supported command line flags which are enumerated in the
578
+ * `config-flags` module. Handles leading dashes on arguments, aliases that are
579
+ * defined for a small number of arguments, and parsing values for non-boolean
580
+ * arguments (e.g. port number for the dev server).
581
+ *
582
+ * This parses the following grammar:
583
+ *
584
+ * CLIArguments → ""
585
+ * | CLITerm ( " " CLITerm )* ;
586
+ * CLITerm → EqualsArg
587
+ * | AliasEqualsArg
588
+ * | AliasArg
589
+ * | NegativeDashArg
590
+ * | NegativeArg
591
+ * | SimpleArg ;
592
+ * EqualsArg → "--" ArgName "=" CLIValue ;
593
+ * AliasEqualsArg → "-" AliasName "=" CLIValue ;
594
+ * AliasArg → "-" AliasName ( " " CLIValue )? ;
595
+ * NegativeDashArg → "--no-" ArgName ;
596
+ * NegativeArg → "--no" ArgName ;
597
+ * SimpleArg → "--" ArgName ( " " CLIValue )? ;
598
+ * ArgName → /^[a-zA-Z-]+$/ ;
599
+ * AliasName → /^[a-z]{1}$/ ;
600
+ * CLIValue → '"' /^[a-zA-Z0-9]+$/ '"'
601
+ * | /^[a-zA-Z0-9]+$/ ;
602
+ *
603
+ * There are additional constraints (not shown in the grammar for brevity's sake)
604
+ * on the type of `CLIValue` which will be associated with a particular argument.
605
+ * We enforce this by declaring lists of boolean, string, etc arguments and
606
+ * checking the types of values before setting them.
607
+ *
608
+ * We don't need to turn the list of CLI arg tokens into any kind of
609
+ * intermediate representation since we aren't concerned with doing anything
610
+ * other than setting the correct values on our ConfigFlags object. So we just
611
+ * parse the array of string arguments using a recursive-descent approach
612
+ * (which is not very deep since our grammar is pretty simple) and make the
613
+ * modifications we need to make to the {@link ConfigFlags} object as we go.
555
614
  *
556
615
  * @param flags a ConfigFlags object to which parsed arguments will be added
557
616
  * @param args an array of command-line arguments to parse
558
617
  */
559
618
  const parseArgs = (flags, args) => {
560
- BOOLEAN_CLI_ARGS.forEach((argName) => parseBooleanArg(flags, args, argName));
561
- STRING_CLI_ARGS.forEach((argName) => parseStringArg(flags, args, argName));
562
- NUMBER_CLI_ARGS.forEach((argName) => parseNumberArg(flags, args, argName));
563
- STRING_NUMBER_CLI_ARGS.forEach((argName) => parseStringNumberArg(flags, args, argName));
564
- LOG_LEVEL_CLI_ARGS.forEach((argName) => parseLogLevelArg(flags, args, argName));
619
+ const argsCopy = args.concat();
620
+ while (argsCopy.length > 0) {
621
+ // there are still unprocessed args to deal with
622
+ parseCLITerm(flags, argsCopy);
623
+ }
565
624
  };
566
625
  /**
567
- * Parse a boolean CLI argument. For these, we support the following formats:
568
- *
569
- * - `--booleanArg`
570
- * - `--boolean-arg`
571
- * - `--noBooleanArg`
572
- * - `--no-boolean-arg`
573
- *
574
- * The final two variants should be parsed to a value of `false` on the config
575
- * object.
626
+ * Given an array of CLI arguments, parse it and perform a series of side
627
+ * effects (setting values on the provided `ConfigFlags` object).
576
628
  *
577
- * @param flags the config flags object, while we'll modify
578
- * @param args our CLI arguments
579
- * @param configCaseName the argument we want to look at right now
580
- */
581
- const parseBooleanArg = (flags, args, configCaseName) => {
582
- // we support both dash-case and PascalCase versions of the parameter
583
- // argName is 'configCase' version which can be found in BOOLEAN_ARG_OPTS
584
- const alias = CLI_ARG_ALIASES[configCaseName];
585
- const dashCaseName = toDashCase(configCaseName);
586
- if (typeof flags[configCaseName] !== 'boolean') {
587
- flags[configCaseName] = null;
588
- }
589
- args.forEach((cmdArg) => {
590
- let value;
591
- if (cmdArg === `--${configCaseName}` || cmdArg === `--${dashCaseName}`) {
592
- value = true;
593
- }
594
- else if (cmdArg === `--no-${dashCaseName}` || cmdArg === `--no${dashToPascalCase(dashCaseName)}`) {
595
- value = false;
596
- }
597
- else if (alias && cmdArg === `-${alias}`) {
598
- value = true;
599
- }
600
- if (value !== undefined && cmdArg !== undefined) {
601
- flags[configCaseName] = value;
602
- flags.knownArgs.push(cmdArg);
603
- }
604
- });
629
+ * @param flags a {@link ConfigFlags} object which is updated as we parse the CLI
630
+ * arguments
631
+ * @param args a list of args to work through. This function (and some functions
632
+ * it calls) calls `Array.prototype.shift` to get the next argument to look at,
633
+ * so this parameter will be modified.
634
+ */
635
+ const parseCLITerm = (flags, args) => {
636
+ // pull off the first arg from the argument array
637
+ const arg = args.shift();
638
+ // array is empty, we're done!
639
+ if (arg === undefined)
640
+ return;
641
+ // EqualsArg → "--" ArgName "=" CLIValue ;
642
+ if (arg.startsWith('--') && arg.includes('=')) {
643
+ // we're dealing with an EqualsArg, we have a special helper for that
644
+ const [originalArg, value] = parseEqualsArg(arg);
645
+ setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);
646
+ }
647
+ // AliasEqualsArg → "-" AliasName "=" CLIValue ;
648
+ else if (arg.startsWith('-') && arg.includes('=')) {
649
+ // we're dealing with an AliasEqualsArg, we have a special helper for that
650
+ const [originalArg, value] = parseEqualsArg(arg);
651
+ setCLIArg(flags, arg.split('=')[0], normalizeFlagName(originalArg), value);
652
+ }
653
+ // AliasArg → "-" AliasName ( " " CLIValue )? ;
654
+ else if (CLI_FLAG_REGEX.test(arg)) {
655
+ // this is a short alias, like `-c` for Config
656
+ setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));
657
+ }
658
+ // NegativeDashArg → "--no-" ArgName ;
659
+ else if (arg.startsWith('--no-') && arg.length > '--no-'.length) {
660
+ // this is a `NegativeDashArg` term, so we need to normalize the negative
661
+ // flag name and then set an appropriate value
662
+ const normalized = normalizeNegativeFlagName(arg);
663
+ setCLIArg(flags, arg, normalized, '');
664
+ }
665
+ // NegativeArg → "--no" ArgName ;
666
+ else if (arg.startsWith('--no') &&
667
+ !readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeFlagName(arg)) &&
668
+ readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizeNegativeFlagName(arg))) {
669
+ // possibly dealing with a `NegativeArg` here. There is a little ambiguity
670
+ // here because we have arguments that already begin with `no` like
671
+ // `notify`, so we need to test if a normalized form of the raw argument is
672
+ // a valid and supported boolean flag.
673
+ setCLIArg(flags, arg, normalizeNegativeFlagName(arg), '');
674
+ }
675
+ // SimpleArg → "--" ArgName ( " " CLIValue )? ;
676
+ else if (arg.startsWith('--') && arg.length > '--'.length) {
677
+ setCLIArg(flags, arg, normalizeFlagName(arg), parseCLIValue(args));
678
+ }
679
+ // if we get here it is not an argument in our list of supported arguments.
680
+ // This doesn't necessarily mean we want to report an error or anything
681
+ // though! Instead, with unknown / unrecognized arguments we stick them into
682
+ // the `unknownArgs` array, which is used when we pass CLI args to Jest, for
683
+ // instance. So we just return void here.
605
684
  };
606
685
  /**
607
- * Parse a string CLI argument
686
+ * Normalize a 'negative' flag name, just to do a little pre-processing before
687
+ * we pass it to `setCLIArg`.
608
688
  *
609
- * @param flags the config flags object, while we'll modify
610
- * @param args our CLI arguments
611
- * @param configCaseName the argument we want to look at right now
689
+ * @param flagName the flag name to normalize
690
+ * @returns a normalized flag name
612
691
  */
613
- const parseStringArg = (flags, args, configCaseName) => {
614
- if (typeof flags[configCaseName] !== 'string') {
615
- flags[configCaseName] = null;
616
- }
617
- const { value, matchingArg } = getValue(args, configCaseName);
618
- if (value !== undefined && matchingArg !== undefined) {
619
- flags[configCaseName] = value;
620
- flags.knownArgs.push(matchingArg);
621
- flags.knownArgs.push(value);
622
- }
692
+ const normalizeNegativeFlagName = (flagName) => {
693
+ const trimmed = flagName.replace(/^--no[-]?/, '');
694
+ return normalizeFlagName(trimmed.charAt(0).toLowerCase() + trimmed.slice(1));
623
695
  };
624
696
  /**
625
- * Parse a number CLI argument
697
+ * Normalize a flag name by:
698
+ *
699
+ * - replacing any leading dashes (`--foo` -> `foo`)
700
+ * - converting `dash-case` to camelCase (if necessary)
701
+ *
702
+ * Normalizing in this context basically means converting the various
703
+ * supported flag spelling variants to the variant defined in our lists of
704
+ * supported arguments (e.g. BOOLEAN_CLI_FLAGS, etc). So, for instance,
705
+ * `--log-level` should be converted to `logLevel`.
706
+ *
707
+ * @param flagName the flag name to normalize
708
+ * @returns a normalized flag name
626
709
  *
627
- * @param flags the config flags object, while we'll modify
628
- * @param args our CLI arguments
629
- * @param configCaseName the argument we want to look at right now
630
710
  */
631
- const parseNumberArg = (flags, args, configCaseName) => {
632
- if (typeof flags[configCaseName] !== 'number') {
633
- flags[configCaseName] = null;
634
- }
635
- const { value, matchingArg } = getValue(args, configCaseName);
636
- if (value !== undefined && matchingArg !== undefined) {
637
- flags[configCaseName] = parseInt(value, 10);
638
- flags.knownArgs.push(matchingArg);
639
- flags.knownArgs.push(value);
640
- }
711
+ const normalizeFlagName = (flagName) => {
712
+ const trimmed = flagName.replace(/^-+/, '');
713
+ return trimmed.includes('-') ? toCamelCase(trimmed) : trimmed;
641
714
  };
642
715
  /**
643
- * Parse a CLI argument which may be either a string or a number
716
+ * Set a value on a provided {@link ConfigFlags} object, given an argument
717
+ * name and a raw string value. This function dispatches to other functions
718
+ * which make sure that the string value can be properly parsed into a JS
719
+ * runtime value of the right type (e.g. number, string, etc).
644
720
  *
645
- * @param flags the config flags object, while we'll modify
646
- * @param args our CLI arguments
647
- * @param configCaseName the argument we want to look at right now
648
- */
649
- const parseStringNumberArg = (flags, args, configCaseName) => {
650
- if (!['number', 'string'].includes(typeof flags[configCaseName])) {
651
- flags[configCaseName] = null;
721
+ * @throws if a value cannot be parsed to the right type for a given flag
722
+ * @param flags a {@link ConfigFlags} object
723
+ * @param rawArg the raw argument name matched by the parser
724
+ * @param normalizedArg an argument with leading control characters (`--`,
725
+ * `--no-`, etc) removed
726
+ * @param value the raw value to be set onto the config flags object
727
+ */
728
+ const setCLIArg = (flags, rawArg, normalizedArg, value) => {
729
+ normalizedArg = dereferenceAlias(normalizedArg);
730
+ // We're setting a boolean!
731
+ if (readOnlyArrayHasStringMember(BOOLEAN_CLI_FLAGS, normalizedArg)) {
732
+ flags[normalizedArg] =
733
+ typeof value === 'string'
734
+ ? Boolean(value)
735
+ : // no value was supplied, default to true
736
+ true;
737
+ flags.knownArgs.push(rawArg);
738
+ }
739
+ // We're setting a string!
740
+ else if (readOnlyArrayHasStringMember(STRING_CLI_FLAGS, normalizedArg)) {
741
+ if (typeof value === 'string') {
742
+ flags[normalizedArg] = value;
743
+ flags.knownArgs.push(rawArg);
744
+ flags.knownArgs.push(value);
745
+ }
746
+ else {
747
+ throwCLIParsingError(rawArg, 'expected a string argument but received nothing');
748
+ }
652
749
  }
653
- const { value, matchingArg } = getValue(args, configCaseName);
654
- if (value !== undefined && matchingArg !== undefined) {
655
- if (CLI_ARG_STRING_REGEX.test(value)) {
656
- // if it matches the regex we treat it like a string
657
- flags[configCaseName] = value;
750
+ // We're setting a string, but it's one where the user can pass multiple values,
751
+ // like `--reporters="default" --reporters="jest-junit"`
752
+ else if (readOnlyArrayHasStringMember(STRING_ARRAY_CLI_FLAGS, normalizedArg)) {
753
+ if (typeof value === 'string') {
754
+ if (!Array.isArray(flags[normalizedArg])) {
755
+ flags[normalizedArg] = [];
756
+ }
757
+ const targetArray = flags[normalizedArg];
758
+ // this is irritating, but TS doesn't know that the `!Array.isArray`
759
+ // check above guarantees we have an array to work with here, and it
760
+ // doesn't want to narrow the type of `flags[normalizedArg]`, so we need
761
+ // to grab a reference to that array and then `Array.isArray` that. Bah!
762
+ if (Array.isArray(targetArray)) {
763
+ targetArray.push(value);
764
+ flags.knownArgs.push(rawArg);
765
+ flags.knownArgs.push(value);
766
+ }
658
767
  }
659
768
  else {
660
- // it was a number, great!
661
- flags[configCaseName] = Number(value);
769
+ throwCLIParsingError(rawArg, 'expected a string argument but received nothing');
770
+ }
771
+ }
772
+ // We're setting a number!
773
+ else if (readOnlyArrayHasStringMember(NUMBER_CLI_FLAGS, normalizedArg)) {
774
+ if (typeof value === 'string') {
775
+ const parsed = parseInt(value, 10);
776
+ if (isNaN(parsed)) {
777
+ throwNumberParsingError(rawArg, value);
778
+ }
779
+ else {
780
+ flags[normalizedArg] = parsed;
781
+ flags.knownArgs.push(rawArg);
782
+ flags.knownArgs.push(value);
783
+ }
784
+ }
785
+ else {
786
+ throwCLIParsingError(rawArg, 'expected a number argument but received nothing');
787
+ }
788
+ }
789
+ // We're setting a value which could be either a string _or_ a number
790
+ else if (readOnlyArrayHasStringMember(STRING_NUMBER_CLI_FLAGS, normalizedArg)) {
791
+ if (typeof value === 'string') {
792
+ if (CLI_ARG_STRING_REGEX.test(value)) {
793
+ // if it matches the regex we treat it like a string
794
+ flags[normalizedArg] = value;
795
+ }
796
+ else {
797
+ const parsed = Number(value);
798
+ if (isNaN(parsed)) {
799
+ // parsing didn't go so well, we gotta get out of here
800
+ // this is unlikely given our regex guard above
801
+ // but hey, this is ultimately JS so let's be safe
802
+ throwNumberParsingError(rawArg, value);
803
+ }
804
+ else {
805
+ flags[normalizedArg] = parsed;
806
+ }
807
+ }
808
+ flags.knownArgs.push(rawArg);
809
+ flags.knownArgs.push(value);
810
+ }
811
+ else {
812
+ throwCLIParsingError(rawArg, 'expected a string or a number but received nothing');
813
+ }
814
+ }
815
+ // We're setting the log level, which can only be a set of specific string values
816
+ else if (readOnlyArrayHasStringMember(LOG_LEVEL_CLI_FLAGS, normalizedArg)) {
817
+ if (typeof value === 'string') {
818
+ if (isLogLevel(value)) {
819
+ flags[normalizedArg] = value;
820
+ flags.knownArgs.push(rawArg);
821
+ flags.knownArgs.push(value);
822
+ }
823
+ else {
824
+ throwCLIParsingError(rawArg, `expected to receive a valid log level but received "${String(value)}"`);
825
+ }
826
+ }
827
+ else {
828
+ throwCLIParsingError(rawArg, 'expected to receive a valid log level but received nothing');
662
829
  }
663
- flags.knownArgs.push(matchingArg);
664
- flags.knownArgs.push(value);
665
830
  }
666
831
  };
667
832
  /**
@@ -682,73 +847,34 @@ const parseStringNumberArg = (flags, args, configCaseName) => {
682
847
  * to a number.
683
848
  */
684
849
  const CLI_ARG_STRING_REGEX = /[^\d\.Ee\+\-]+/g;
850
+ const Empty = Symbol('Empty');
685
851
  /**
686
- * Parse a LogLevel CLI argument. These can be only a specific
687
- * set of strings, so this function takes care of validating that
688
- * the value is correct.
852
+ * A little helper which tries to parse a CLI value (as opposed to a flag) off
853
+ * of the argument array.
689
854
  *
690
- * @param flags the config flags object, while we'll modify
691
- * @param args our CLI arguments
692
- * @param configCaseName the argument we want to look at right now
693
- */
694
- const parseLogLevelArg = (flags, args, configCaseName) => {
695
- if (typeof flags[configCaseName] !== 'string') {
696
- flags[configCaseName] = null;
697
- }
698
- const { value, matchingArg } = getValue(args, configCaseName);
699
- if (value !== undefined && matchingArg !== undefined && isLogLevel(value)) {
700
- flags[configCaseName] = value;
701
- flags.knownArgs.push(matchingArg);
702
- flags.knownArgs.push(value);
703
- }
704
- };
705
- /**
706
- * Helper for pulling values out from the raw array of CLI arguments. This logic
707
- * is shared between a few different types of CLI args.
708
- *
709
- * We look for arguments in the following formats:
710
- *
711
- * - `--my-cli-argument value`
712
- * - `--my-cli-argument=value`
713
- * - `--myCliArgument value`
714
- * - `--myCliArgument=value`
715
- *
716
- * We also check for shortened aliases, which we define for a few arguments.
717
- *
718
- * @param args the CLI args we're dealing with
719
- * @param configCaseName the ConfigFlag key which we're looking to pull out a value for
720
- * @returns the value for the flag as well as the exact string which it matched from
721
- * the user input.
722
- */
723
- const getValue = (args, configCaseName) => {
724
- // for some CLI args we have a short alias, like 'c' for 'config'
725
- const alias = CLI_ARG_ALIASES[configCaseName];
726
- // we support supplying arguments in both dash-case and configCase
727
- // for ease of use
728
- const dashCaseName = toDashCase(configCaseName);
729
- let value;
730
- let matchingArg;
731
- args.forEach((arg, i) => {
732
- if (arg.startsWith(`--${dashCaseName}=`) || arg.startsWith(`--${configCaseName}=`)) {
733
- // our argument was passed at the command-line in the format --argName=arg-value
734
- [matchingArg, value] = parseEqualsArg(arg);
735
- }
736
- else if (arg === `--${dashCaseName}` || arg === `--${configCaseName}`) {
737
- // the next value in the array is assumed to be a value for this argument
738
- value = args[i + 1];
739
- matchingArg = arg;
740
- }
741
- else if (alias) {
742
- if (arg.startsWith(`-${alias}=`)) {
743
- [matchingArg, value] = parseEqualsArg(arg);
744
- }
745
- else if (arg === `-${alias}`) {
746
- value = args[i + 1];
747
- matchingArg = arg;
748
- }
855
+ * We support a variety of different argument formats, but all of them start
856
+ * with `-`, so we can check the first character to test whether the next token
857
+ * in our array of CLI arguments is a flag name or a value.
858
+ *
859
+ * @param args an array of CLI args
860
+ * @returns either a string result or an Empty sentinel
861
+ */
862
+ const parseCLIValue = (args) => {
863
+ // it's possible the arguments array is empty, if so, return empty
864
+ if (args[0] === undefined) {
865
+ return Empty;
866
+ }
867
+ // all we're concerned with here is that it does not start with `"-"`,
868
+ // which would indicate it should be parsed as a CLI flag and not a value.
869
+ if (!args[0].startsWith('-')) {
870
+ // It's not a flag, so we return the value and defer any specific parsing
871
+ // until later on.
872
+ const value = args.shift();
873
+ if (typeof value === 'string') {
874
+ return value;
749
875
  }
750
- });
751
- return { value, matchingArg };
876
+ }
877
+ return Empty;
752
878
  };
753
879
  /**
754
880
  * Parse an 'equals' argument, which is a CLI argument-value pair in the
@@ -784,8 +910,9 @@ const getValue = (args, configCaseName) => {
784
910
  * @returns a tuple containing the arg name and the value (if present)
785
911
  */
786
912
  const parseEqualsArg = (arg) => {
787
- const [originalArg, ...value] = arg.split('=');
788
- return [originalArg, value.join('=')];
913
+ const [originalArg, ...splitSections] = arg.split('=');
914
+ const value = splitSections.join('=');
915
+ return [originalArg, value === '' ? Empty : value];
789
916
  };
790
917
  /**
791
918
  * Small helper for getting type-system-level assurance that a `string` can be
@@ -794,18 +921,51 @@ const parseEqualsArg = (arg) => {
794
921
  * @param maybeLogLevel the string to check
795
922
  * @returns whether this is a `LogLevel`
796
923
  */
797
- const isLogLevel = (maybeLogLevel) =>
798
- // unfortunately `includes` is typed on `ReadonlyArray<T>` as `(el: T):
799
- // boolean` so a `string` cannot be passed to `includes` on a
800
- // `ReadonlyArray` 😢 thus we `as any`
801
- //
802
- // see microsoft/TypeScript#31018 for some discussion of this
803
- LOG_LEVELS.includes(maybeLogLevel);
924
+ const isLogLevel = (maybeLogLevel) => readOnlyArrayHasStringMember(LOG_LEVELS, maybeLogLevel);
925
+ /**
926
+ * A little helper for constructing and throwing an error message with info
927
+ * about what went wrong
928
+ *
929
+ * @param flag the flag which encountered the error
930
+ * @param message a message specific to the error which was encountered
931
+ */
932
+ const throwCLIParsingError = (flag, message) => {
933
+ throw new Error(`when parsing CLI flag "${flag}": ${message}`);
934
+ };
935
+ /**
936
+ * Throw a specific error for the situation where we ran into an issue parsing
937
+ * a number.
938
+ *
939
+ * @param flag the flag for which we encountered the issue
940
+ * @param value what we were trying to parse
941
+ */
942
+ const throwNumberParsingError = (flag, value) => {
943
+ throwCLIParsingError(flag, `expected a number but received "${value}"`);
944
+ };
945
+ /**
946
+ * A little helper to 'dereference' a flag alias, which if you squint a little
947
+ * you can think of like a pointer to a full flag name. Thus 'c' is like a
948
+ * pointer to 'config', so here we're doing something like `*c`. Of course, this
949
+ * being JS, this is just a metaphor!
950
+ *
951
+ * If no 'dereference' is found for the possible alias we just return the
952
+ * passed string unmodified.
953
+ *
954
+ * @param maybeAlias a string which _could_ be an alias to a full flag name
955
+ * @returns the full aliased flag name, if found, or the passed string if not
956
+ */
957
+ const dereferenceAlias = (maybeAlias) => {
958
+ const possibleDereference = CLI_FLAG_ALIASES[maybeAlias];
959
+ if (typeof possibleDereference === 'string') {
960
+ return possibleDereference;
961
+ }
962
+ return maybeAlias;
963
+ };
804
964
 
805
965
  const dependencies = [
806
966
  {
807
967
  name: "@rindo/core",
808
- version: "2.17.4",
968
+ version: "2.22.2",
809
969
  main: "compiler/rindo.js",
810
970
  resources: [
811
971
  "package.json",
@@ -842,13 +1002,16 @@ const dependencies = [
842
1002
  "compiler/lib.es2019.array.d.ts",
843
1003
  "compiler/lib.es2019.d.ts",
844
1004
  "compiler/lib.es2019.full.d.ts",
1005
+ "compiler/lib.es2019.intl.d.ts",
845
1006
  "compiler/lib.es2019.object.d.ts",
846
1007
  "compiler/lib.es2019.string.d.ts",
847
1008
  "compiler/lib.es2019.symbol.d.ts",
848
1009
  "compiler/lib.es2020.bigint.d.ts",
849
1010
  "compiler/lib.es2020.d.ts",
1011
+ "compiler/lib.es2020.date.d.ts",
850
1012
  "compiler/lib.es2020.full.d.ts",
851
1013
  "compiler/lib.es2020.intl.d.ts",
1014
+ "compiler/lib.es2020.number.d.ts",
852
1015
  "compiler/lib.es2020.promise.d.ts",
853
1016
  "compiler/lib.es2020.sharedmemory.d.ts",
854
1017
  "compiler/lib.es2020.string.d.ts",
@@ -859,6 +1022,14 @@ const dependencies = [
859
1022
  "compiler/lib.es2021.promise.d.ts",
860
1023
  "compiler/lib.es2021.string.d.ts",
861
1024
  "compiler/lib.es2021.weakref.d.ts",
1025
+ "compiler/lib.es2022.array.d.ts",
1026
+ "compiler/lib.es2022.d.ts",
1027
+ "compiler/lib.es2022.error.d.ts",
1028
+ "compiler/lib.es2022.full.d.ts",
1029
+ "compiler/lib.es2022.intl.d.ts",
1030
+ "compiler/lib.es2022.object.d.ts",
1031
+ "compiler/lib.es2022.sharedmemory.d.ts",
1032
+ "compiler/lib.es2022.string.d.ts",
862
1033
  "compiler/lib.es5.d.ts",
863
1034
  "compiler/lib.es6.d.ts",
864
1035
  "compiler/lib.esnext.d.ts",
@@ -903,16 +1074,112 @@ const dependencies = [
903
1074
  },
904
1075
  {
905
1076
  name: "terser",
906
- version: "5.6.1",
1077
+ version: "5.16.1",
907
1078
  main: "dist/bundle.min.js"
908
1079
  },
909
1080
  {
910
1081
  name: "typescript",
911
- version: "4.5.4",
1082
+ version: "4.9.4",
912
1083
  main: "lib/typescript.js"
913
1084
  }
914
1085
  ];
915
1086
 
1087
+ const IS_NODE_ENV = typeof global !== 'undefined' &&
1088
+ typeof require === 'function' &&
1089
+ !!global.process &&
1090
+ typeof __filename === 'string' &&
1091
+ (!global.origin || typeof global.origin !== 'string');
1092
+ const IS_BROWSER_ENV = typeof location !== 'undefined' && typeof navigator !== 'undefined' && typeof XMLHttpRequest !== 'undefined';
1093
+
1094
+ /**
1095
+ * Creates an instance of a logger
1096
+ * @returns the new logger instance
1097
+ */
1098
+ const createLogger = () => {
1099
+ let useColors = IS_BROWSER_ENV;
1100
+ let level = 'info';
1101
+ return {
1102
+ enableColors: (uc) => (useColors = uc),
1103
+ getLevel: () => level,
1104
+ setLevel: (l) => (level = l),
1105
+ emoji: (e) => e,
1106
+ info: console.log.bind(console),
1107
+ warn: console.warn.bind(console),
1108
+ error: console.error.bind(console),
1109
+ debug: console.debug.bind(console),
1110
+ red: (msg) => msg,
1111
+ green: (msg) => msg,
1112
+ yellow: (msg) => msg,
1113
+ blue: (msg) => msg,
1114
+ magenta: (msg) => msg,
1115
+ cyan: (msg) => msg,
1116
+ gray: (msg) => msg,
1117
+ bold: (msg) => msg,
1118
+ dim: (msg) => msg,
1119
+ bgRed: (msg) => msg,
1120
+ createTimeSpan: (_startMsg, _debug = false) => ({
1121
+ duration: () => 0,
1122
+ finish: () => 0,
1123
+ }),
1124
+ printDiagnostics(diagnostics) {
1125
+ diagnostics.forEach((diagnostic) => logDiagnostic(diagnostic, useColors));
1126
+ },
1127
+ };
1128
+ };
1129
+ const logDiagnostic = (diagnostic, useColors) => {
1130
+ let color = BLUE;
1131
+ let prefix = 'Build';
1132
+ let msg = '';
1133
+ if (diagnostic.level === 'error') {
1134
+ color = RED;
1135
+ prefix = 'Error';
1136
+ }
1137
+ else if (diagnostic.level === 'warn') {
1138
+ color = YELLOW;
1139
+ prefix = 'Warning';
1140
+ }
1141
+ if (diagnostic.header) {
1142
+ prefix = diagnostic.header;
1143
+ }
1144
+ const filePath = diagnostic.relFilePath || diagnostic.absFilePath;
1145
+ if (filePath) {
1146
+ msg += filePath;
1147
+ if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > 0) {
1148
+ msg += ', line ' + diagnostic.lineNumber;
1149
+ if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > 0) {
1150
+ msg += ', column ' + diagnostic.columnNumber;
1151
+ }
1152
+ }
1153
+ msg += '\n';
1154
+ }
1155
+ msg += diagnostic.messageText;
1156
+ if (diagnostic.lines && diagnostic.lines.length > 0) {
1157
+ diagnostic.lines.forEach((l) => {
1158
+ msg += '\n' + l.lineNumber + ': ' + l.text;
1159
+ });
1160
+ msg += '\n';
1161
+ }
1162
+ if (useColors) {
1163
+ const styledPrefix = [
1164
+ '%c' + prefix,
1165
+ `background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`,
1166
+ ];
1167
+ console.log(...styledPrefix, msg);
1168
+ }
1169
+ else if (diagnostic.level === 'error') {
1170
+ console.error(msg);
1171
+ }
1172
+ else if (diagnostic.level === 'warn') {
1173
+ console.warn(msg);
1174
+ }
1175
+ else {
1176
+ console.log(msg);
1177
+ }
1178
+ };
1179
+ const YELLOW = `#f39c12`;
1180
+ const RED = `#c0392b`;
1181
+ const BLUE = `#3498db`;
1182
+
916
1183
  /**
917
1184
  * Attempt to find a Rindo configuration file on the file system
918
1185
  * @param opts the options needed to find the configuration file
@@ -921,11 +1188,7 @@ const dependencies = [
921
1188
  const findConfig = async (opts) => {
922
1189
  const sys = opts.sys;
923
1190
  const cwd = sys.getCurrentDirectory();
924
- const results = {
925
- configPath: null,
926
- rootDir: normalizePath(cwd),
927
- diagnostics: [],
928
- };
1191
+ const rootDir = normalizePath(cwd);
929
1192
  let configPath = opts.configPath;
930
1193
  if (isString(configPath)) {
931
1194
  if (!sys.platformPath.isAbsolute(configPath)) {
@@ -940,8 +1203,13 @@ const findConfig = async (opts) => {
940
1203
  }
941
1204
  else {
942
1205
  // nothing was passed in, use the current working directory
943
- configPath = results.rootDir;
1206
+ configPath = rootDir;
944
1207
  }
1208
+ const results = {
1209
+ configPath,
1210
+ rootDir: normalizePath(cwd),
1211
+ diagnostics: [],
1212
+ };
945
1213
  const stat = await sys.stat(configPath);
946
1214
  if (stat.error) {
947
1215
  const diagnostic = buildError(results.diagnostics);
@@ -974,12 +1242,33 @@ const loadCoreCompiler = async (sys) => {
974
1242
  return globalThis.rindo;
975
1243
  };
976
1244
 
1245
+ /**
1246
+ * Log the name of this package (`@rindo/core`) to an output stream
1247
+ *
1248
+ * The output stream is determined by the {@link Logger} instance that is provided as an argument to this function
1249
+ *
1250
+ * The name of the package may not be logged, by design, for certain `task` types and logging levels
1251
+ *
1252
+ * @param logger the logging entity to use to output the name of the package
1253
+ * @param task the current task
1254
+ */
977
1255
  const startupLog = (logger, task) => {
978
1256
  if (task === 'info' || task === 'serve' || task === 'version') {
979
1257
  return;
980
1258
  }
981
1259
  logger.info(logger.cyan(`@rindo/core`));
982
1260
  };
1261
+ /**
1262
+ * Log this package's version to an output stream
1263
+ *
1264
+ * The output stream is determined by the {@link Logger} instance that is provided as an argument to this function
1265
+ *
1266
+ * The package version may not be logged, by design, for certain `task` types and logging levels
1267
+ *
1268
+ * @param logger the logging entity to use for output
1269
+ * @param task the current task
1270
+ * @param coreCompiler the compiler instance to derive version information from
1271
+ */
983
1272
  const startupLogVersion = (logger, task, coreCompiler) => {
984
1273
  if (task === 'info' || task === 'serve' || task === 'version') {
985
1274
  return;
@@ -995,11 +1284,25 @@ const startupLogVersion = (logger, task, coreCompiler) => {
995
1284
  startupMsg += logger.emoji(' ' + coreCompiler.vermoji);
996
1285
  logger.info(startupMsg);
997
1286
  };
1287
+ /**
1288
+ * Log details from a {@link CompilerSystem} used by Rindo to an output stream
1289
+ *
1290
+ * The output stream is determined by the {@link Logger} instance that is provided as an argument to this function
1291
+ *
1292
+ * @param sys the `CompilerSystem` to report details on
1293
+ * @param logger the logging entity to use for output
1294
+ * @param flags user set flags for the current invocation of Rindo
1295
+ * @param coreCompiler the compiler instance being used for this invocation of Rindo
1296
+ */
998
1297
  const loadedCompilerLog = (sys, logger, flags, coreCompiler) => {
999
1298
  const sysDetails = sys.details;
1000
1299
  const runtimeInfo = `${sys.name} ${sys.version}`;
1001
- const platformInfo = `${sysDetails.platform}, ${sysDetails.cpuModel}`;
1002
- const statsInfo = `cpus: ${sys.hardwareConcurrency}, freemem: ${Math.round(sysDetails.freemem() / 1000000)}MB, totalmem: ${Math.round(sysDetails.totalmem / 1000000)}MB`;
1300
+ const platformInfo = sysDetails
1301
+ ? `${sysDetails.platform}, ${sysDetails.cpuModel}`
1302
+ : `Unknown Platform, Unknown CPU Model`;
1303
+ const statsInfo = sysDetails
1304
+ ? `cpus: ${sys.hardwareConcurrency}, freemem: ${Math.round(sysDetails.freemem() / 1000000)}MB, totalmem: ${Math.round(sysDetails.totalmem / 1000000)}MB`
1305
+ : 'Unknown CPU Core Count, Unknown Memory';
1003
1306
  if (logger.getLevel() === 'debug') {
1004
1307
  logger.debug(runtimeInfo);
1005
1308
  logger.debug(platformInfo);
@@ -1013,6 +1316,14 @@ const loadedCompilerLog = (sys, logger, flags, coreCompiler) => {
1013
1316
  logger.info(statsInfo);
1014
1317
  }
1015
1318
  };
1319
+ /**
1320
+ * Log various warnings to an output stream
1321
+ *
1322
+ * The output stream is determined by the {@link Logger} instance attached to the `config` argument to this function
1323
+ *
1324
+ * @param coreCompiler the compiler instance being used for this invocation of Rindo
1325
+ * @param config a validated configuration object to be used for this run of Rindo
1326
+ */
1016
1327
  const startupCompilerLog = (coreCompiler, config) => {
1017
1328
  if (config.suppressLogs === true) {
1018
1329
  return;
@@ -1034,6 +1345,21 @@ const startupCompilerLog = (coreCompiler, config) => {
1034
1345
  }
1035
1346
  };
1036
1347
 
1348
+ const startCheckVersion = async (config, currentVersion) => {
1349
+ if (config.devMode && !config.flags.ci && !currentVersion.includes('-dev.') && isFunction(config.sys.checkVersion)) {
1350
+ return config.sys.checkVersion(config.logger, currentVersion);
1351
+ }
1352
+ return null;
1353
+ };
1354
+ const printCheckVersionResults = async (versionChecker) => {
1355
+ if (versionChecker) {
1356
+ const checkVersionResults = await versionChecker;
1357
+ if (isFunction(checkVersionResults)) {
1358
+ checkVersionResults();
1359
+ }
1360
+ }
1361
+ };
1362
+
1037
1363
  const taskPrerender = async (coreCompiler, config) => {
1038
1364
  startupCompilerLog(coreCompiler, config);
1039
1365
  const hydrateAppFilePath = config.flags.unknownArgs[0];
@@ -1065,21 +1391,6 @@ const runPrerenderTask = async (coreCompiler, config, hydrateAppFilePath, compon
1065
1391
  return diagnostics;
1066
1392
  };
1067
1393
 
1068
- const startCheckVersion = async (config, currentVersion) => {
1069
- if (config.devMode && !config.flags.ci && !currentVersion.includes('-dev.') && isFunction(config.sys.checkVersion)) {
1070
- return config.sys.checkVersion(config.logger, currentVersion);
1071
- }
1072
- return null;
1073
- };
1074
- const printCheckVersionResults = async (versionChecker) => {
1075
- if (versionChecker) {
1076
- const checkVersionResults = await versionChecker;
1077
- if (isFunction(checkVersionResults)) {
1078
- checkVersionResults();
1079
- }
1080
- }
1081
- };
1082
-
1083
1394
  const taskWatch = async (coreCompiler, config) => {
1084
1395
  let devServer = null;
1085
1396
  let exitCode = 0;
@@ -1126,6 +1437,15 @@ const taskWatch = async (coreCompiler, config) => {
1126
1437
  }
1127
1438
  };
1128
1439
 
1440
+ const isOutputTargetHydrate = (o) => o.type === DIST_HYDRATE_SCRIPT;
1441
+ const isOutputTargetDocs = (o) => o.type === DOCS_README || o.type === DOCS_JSON || o.type === DOCS_CUSTOM || o.type === DOCS_VSCODE;
1442
+ const DIST_HYDRATE_SCRIPT = 'dist-hydrate-script';
1443
+ const DOCS_CUSTOM = 'docs-custom';
1444
+ const DOCS_JSON = 'docs-json';
1445
+ const DOCS_README = 'docs-readme';
1446
+ const DOCS_VSCODE = 'docs-vscode';
1447
+ const WWW = 'www';
1448
+
1129
1449
  const tryFn = async (fn, ...args) => {
1130
1450
  try {
1131
1451
  return await fn(...args);
@@ -1139,12 +1459,12 @@ const isInteractive = (sys, flags, object) => {
1139
1459
  const terminalInfo = object ||
1140
1460
  Object.freeze({
1141
1461
  tty: sys.isTTY() ? true : false,
1142
- ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => !!sys.getEnvironmentVar(v)).length > 0 || !!flags.ci,
1462
+ ci: ['CI', 'BUILD_ID', 'BUILD_NUMBER', 'BITBUCKET_COMMIT', 'CODEBUILD_BUILD_ARN'].filter((v) => { var _a; return !!((_a = sys.getEnvironmentVar) === null || _a === void 0 ? void 0 : _a.call(sys, v)); }).length > 0 || !!flags.ci,
1143
1463
  });
1144
1464
  return terminalInfo.tty && !terminalInfo.ci;
1145
1465
  };
1146
1466
  const UUID_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i);
1147
- // Plucked from https://github.com/navify/jigra/blob/HEAD/cli/src/util/uuid.ts
1467
+ // Plucked from https://github.com/familyjs/jigra/blob/HEAD/cli/src/util/uuid.ts
1148
1468
  function uuidv4() {
1149
1469
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
1150
1470
  const r = (Math.random() * 16) | 0;
@@ -1168,7 +1488,7 @@ async function readJson(sys, path) {
1168
1488
  * @returns true if --debug has been passed, otherwise false
1169
1489
  */
1170
1490
  function hasDebug(flags) {
1171
- return flags.debug;
1491
+ return !!flags.debug;
1172
1492
  }
1173
1493
  /**
1174
1494
  * Does the command have the verbose and debug flags?
@@ -1176,25 +1496,14 @@ function hasDebug(flags) {
1176
1496
  * @returns true if both --debug and --verbose have been passed, otherwise false
1177
1497
  */
1178
1498
  function hasVerbose(flags) {
1179
- return flags.verbose && hasDebug(flags);
1180
- }
1181
-
1182
- /**
1183
- * Used to determine if tracking should occur.
1184
- * @param config The config passed into the Rindo command
1185
- * @param sys The system where the command is invoked
1186
- * @param ci whether or not the process is running in a Continuous Integration (CI) environment
1187
- * @returns true if telemetry should be sent, false otherwise
1188
- */
1189
- async function shouldTrack(config, sys, ci) {
1190
- return !ci && isInteractive(sys, config.flags) && (await checkTelemetry(sys));
1499
+ return !!flags.verbose && hasDebug(flags);
1191
1500
  }
1192
1501
 
1193
1502
  const isTest$1 = () => process.env.JEST_WORKER_ID !== undefined;
1194
- const defaultConfig = (sys) => sys.resolvePath(`${sys.homeDir()}/.navify/${isTest$1() ? 'tmp-config.json' : 'config.json'}`);
1195
- const defaultConfigDirectory = (sys) => sys.resolvePath(`${sys.homeDir()}/.navify`);
1503
+ const defaultConfig = (sys) => sys.resolvePath(`${sys.homeDir()}/.family/${isTest$1() ? 'tmp-config.json' : 'config.json'}`);
1504
+ const defaultConfigDirectory = (sys) => sys.resolvePath(`${sys.homeDir()}/.family`);
1196
1505
  /**
1197
- * Reads an Navify configuration file from disk, parses it, and performs any necessary corrections to it if certain
1506
+ * Reads an Family configuration file from disk, parses it, and performs any necessary corrections to it if certain
1198
1507
  * values are deemed to be malformed
1199
1508
  * @param sys The system where the command is invoked
1200
1509
  * @returns the config read from disk that has been potentially been updated
@@ -1208,7 +1517,7 @@ async function readConfig(sys) {
1208
1517
  };
1209
1518
  await writeConfig(sys, config);
1210
1519
  }
1211
- else if (!UUID_REGEX.test(config['tokens.telemetry'])) {
1520
+ else if (!config['tokens.telemetry'] || !UUID_REGEX.test(config['tokens.telemetry'])) {
1212
1521
  const newUuid = uuidv4();
1213
1522
  await writeConfig(sys, { ...config, 'tokens.telemetry': newUuid });
1214
1523
  config['tokens.telemetry'] = newUuid;
@@ -1216,7 +1525,7 @@ async function readConfig(sys) {
1216
1525
  return config;
1217
1526
  }
1218
1527
  /**
1219
- * Writes an Navify configuration file to disk.
1528
+ * Writes an Family configuration file to disk.
1220
1529
  * @param sys The system where the command is invoked
1221
1530
  * @param config The config passed into the Rindo command
1222
1531
  * @returns boolean If the command was successful
@@ -1234,7 +1543,7 @@ async function writeConfig(sys, config) {
1234
1543
  return result;
1235
1544
  }
1236
1545
  /**
1237
- * Update a subset of the Navify config.
1546
+ * Update a subset of the Family config.
1238
1547
  * @param sys The system where the command is invoked
1239
1548
  * @param newOptions The new options to save
1240
1549
  * @returns boolean If the command was successful
@@ -1244,14 +1553,16 @@ async function updateConfig(sys, newOptions) {
1244
1553
  return await writeConfig(sys, Object.assign(config, newOptions));
1245
1554
  }
1246
1555
 
1247
- const isOutputTargetHydrate = (o) => o.type === DIST_HYDRATE_SCRIPT;
1248
- const isOutputTargetDocs = (o) => o.type === DOCS_README || o.type === DOCS_JSON || o.type === DOCS_CUSTOM || o.type === DOCS_VSCODE;
1249
- const DIST_HYDRATE_SCRIPT = 'dist-hydrate-script';
1250
- const DOCS_CUSTOM = 'docs-custom';
1251
- const DOCS_JSON = 'docs-json';
1252
- const DOCS_README = 'docs-readme';
1253
- const DOCS_VSCODE = 'docs-vscode';
1254
- const WWW = 'www';
1556
+ /**
1557
+ * Used to determine if tracking should occur.
1558
+ * @param config The config passed into the Rindo command
1559
+ * @param sys The system where the command is invoked
1560
+ * @param ci whether or not the process is running in a Continuous Integration (CI) environment
1561
+ * @returns true if telemetry should be sent, false otherwise
1562
+ */
1563
+ async function shouldTrack(config, sys, ci) {
1564
+ return !ci && isInteractive(sys, config.flags) && (await checkTelemetry(sys));
1565
+ }
1255
1566
 
1256
1567
  /**
1257
1568
  * Used to within taskBuild to provide the component_count property.
@@ -1262,11 +1573,11 @@ const WWW = 'www';
1262
1573
  * @param result The results of a compiler build.
1263
1574
  */
1264
1575
  async function telemetryBuildFinishedAction(sys, config, coreCompiler, result) {
1265
- const tracking = await shouldTrack(config, sys, config.flags.ci);
1576
+ const tracking = await shouldTrack(config, sys, !!config.flags.ci);
1266
1577
  if (!tracking) {
1267
1578
  return;
1268
1579
  }
1269
- const component_count = Object.keys(result.componentGraph).length;
1580
+ const component_count = result.componentGraph ? Object.keys(result.componentGraph).length : undefined;
1270
1581
  const data = await prepareData(coreCompiler, config, sys, result.duration, component_count);
1271
1582
  await sendMetric(sys, config, 'rindo_cli_command', data);
1272
1583
  config.logger.debug(`${config.logger.blue('Telemetry')}: ${config.logger.gray(JSON.stringify(data))}`);
@@ -1345,38 +1656,41 @@ function getActiveTargets(config) {
1345
1656
  * @returns a Promise wrapping data for the telemetry endpoint
1346
1657
  */
1347
1658
  const prepareData = async (coreCompiler, config, sys, duration_ms, component_count = undefined) => {
1659
+ var _a, _b, _c;
1348
1660
  const { typescript, rollup } = coreCompiler.versions || { typescript: 'unknown', rollup: 'unknown' };
1349
1661
  const { packages, packagesNoVersions } = await getInstalledPackages(sys, config);
1350
1662
  const targets = getActiveTargets(config);
1351
1663
  const yarn = isUsingYarn(sys);
1352
1664
  const rindo = coreCompiler.version || 'unknown';
1353
1665
  const system = `${sys.name} ${sys.version}`;
1354
- const os_name = sys.details.platform;
1355
- const os_version = sys.details.release;
1356
- const cpu_model = sys.details.cpuModel;
1666
+ const os_name = (_a = sys.details) === null || _a === void 0 ? void 0 : _a.platform;
1667
+ const os_version = (_b = sys.details) === null || _b === void 0 ? void 0 : _b.release;
1668
+ const cpu_model = (_c = sys.details) === null || _c === void 0 ? void 0 : _c.cpuModel;
1357
1669
  const build = coreCompiler.buildId || 'unknown';
1358
1670
  const has_app_pwa_config = hasAppTarget(config);
1359
1671
  const anonymizedConfig = anonymizeConfigForTelemetry(config);
1672
+ const is_browser_env = IS_BROWSER_ENV;
1360
1673
  return {
1361
- yarn,
1362
- duration_ms,
1674
+ arguments: config.flags.args,
1675
+ build,
1363
1676
  component_count,
1364
- targets,
1677
+ config: anonymizedConfig,
1678
+ cpu_model,
1679
+ duration_ms,
1680
+ has_app_pwa_config,
1681
+ is_browser_env,
1682
+ os_name,
1683
+ os_version,
1365
1684
  packages,
1366
1685
  packages_no_versions: packagesNoVersions,
1367
- arguments: config.flags.args,
1368
- task: config.flags.task,
1686
+ rollup,
1369
1687
  rindo,
1370
1688
  system,
1371
1689
  system_major: getMajorVersion(system),
1372
- os_name,
1373
- os_version,
1374
- cpu_model,
1375
- build,
1690
+ targets,
1691
+ task: config.flags.task,
1376
1692
  typescript,
1377
- rollup,
1378
- has_app_pwa_config,
1379
- config: anonymizedConfig,
1693
+ yarn,
1380
1694
  };
1381
1695
  };
1382
1696
  // props in output targets for which we retain their original values when
@@ -1400,7 +1714,16 @@ const CONFIG_PROPS_TO_ANONYMIZE = [
1400
1714
  // Props we delete entirely from the config for telemetry
1401
1715
  //
1402
1716
  // TODO: Investigate improving anonymization for tsCompilerOptions and devServer
1403
- const CONFIG_PROPS_TO_DELETE = ['sys', 'logger', 'tsCompilerOptions', 'devServer'];
1717
+ const CONFIG_PROPS_TO_DELETE = [
1718
+ 'commonjs',
1719
+ 'devServer',
1720
+ 'env',
1721
+ 'logger',
1722
+ 'rollupConfig',
1723
+ 'sys',
1724
+ 'testing',
1725
+ 'tsCompilerOptions',
1726
+ ];
1404
1727
  /**
1405
1728
  * Anonymize the config for telemetry, replacing potentially revealing config props
1406
1729
  * with a placeholder string if they are present (this lets us still track how frequently
@@ -1450,7 +1773,7 @@ const anonymizeConfigForTelemetry = (config) => {
1450
1773
  /**
1451
1774
  * Reads package-lock.json, yarn.lock, and package.json files in order to cross-reference
1452
1775
  * the dependencies and devDependencies properties. Pulls up the current installed version
1453
- * of each package under the @rindo, @navify, and @jigra scopes.
1776
+ * of each package under the @rindo, @familyjs, and @jigra scopes.
1454
1777
  *
1455
1778
  * @param sys the system instance where telemetry is invoked
1456
1779
  * @param config the Rindo configuration associated with the current task that triggered telemetry
@@ -1472,16 +1795,16 @@ async function getInstalledPackages(sys, config) {
1472
1795
  ...packageJson.devDependencies,
1473
1796
  ...packageJson.dependencies,
1474
1797
  });
1475
- // Collect packages only in the rindo, navify, or jigra org's:
1798
+ // Collect packages only in the rindo, familyjs, or jigra org's:
1476
1799
  // https://www.npmjs.com/org/rindo
1477
- const navifyPackages = rawPackages.filter(([k]) => k.startsWith('@rindo/') || k.startsWith('@navify/') || k.startsWith('@jigra/'));
1800
+ const familyPackages = rawPackages.filter(([k]) => k.startsWith('@rindo/') || k.startsWith('@familyjs/') || k.startsWith('@jigra/'));
1478
1801
  try {
1479
- packages = yarn ? await yarnPackages(sys, navifyPackages) : await npmPackages(sys, navifyPackages);
1802
+ packages = yarn ? await yarnPackages(sys, familyPackages) : await npmPackages(sys, familyPackages);
1480
1803
  }
1481
1804
  catch (e) {
1482
- packages = navifyPackages.map(([k, v]) => `${k}@${v.replace('^', '')}`);
1805
+ packages = familyPackages.map(([k, v]) => `${k}@${v.replace('^', '')}`);
1483
1806
  }
1484
- packagesNoVersions = navifyPackages.map(([k]) => `${k}`);
1807
+ packagesNoVersions = familyPackages.map(([k]) => `${k}`);
1485
1808
  return { packages, packagesNoVersions };
1486
1809
  }
1487
1810
  catch (err) {
@@ -1492,13 +1815,13 @@ async function getInstalledPackages(sys, config) {
1492
1815
  /**
1493
1816
  * Visits the npm lock file to find the exact versions that are installed
1494
1817
  * @param sys The system where the command is invoked
1495
- * @param navifyPackages a list of the found packages matching `@rindo`, `@jigra`, or `@navify` from the package.json file.
1818
+ * @param familyPackages a list of the found packages matching `@rindo`, `@jigra`, or `@familyjs` from the package.json file.
1496
1819
  * @returns an array of strings of all the packages and their versions.
1497
1820
  */
1498
- async function npmPackages(sys, navifyPackages) {
1821
+ async function npmPackages(sys, familyPackages) {
1499
1822
  const appRootDir = sys.getCurrentDirectory();
1500
1823
  const packageLockJson = await tryFn(readJson, sys, sys.resolvePath(appRootDir + '/package-lock.json'));
1501
- return navifyPackages.map(([k, v]) => {
1824
+ return familyPackages.map(([k, v]) => {
1502
1825
  var _a, _b, _c, _d;
1503
1826
  let version = (_d = (_b = (_a = packageLockJson === null || packageLockJson === void 0 ? void 0 : packageLockJson.dependencies[k]) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : (_c = packageLockJson === null || packageLockJson === void 0 ? void 0 : packageLockJson.devDependencies[k]) === null || _c === void 0 ? void 0 : _c.version) !== null && _d !== void 0 ? _d : v;
1504
1827
  version = version.includes('file:') ? sanitizeDeclaredVersion(v) : version;
@@ -1508,14 +1831,14 @@ async function npmPackages(sys, navifyPackages) {
1508
1831
  /**
1509
1832
  * Visits the yarn lock file to find the exact versions that are installed
1510
1833
  * @param sys The system where the command is invoked
1511
- * @param navifyPackages a list of the found packages matching `@rindo`, `@jigra`, or `@navify` from the package.json file.
1834
+ * @param familyPackages a list of the found packages matching `@rindo`, `@jigra`, or `@familyjs` from the package.json file.
1512
1835
  * @returns an array of strings of all the packages and their versions.
1513
1836
  */
1514
- async function yarnPackages(sys, navifyPackages) {
1837
+ async function yarnPackages(sys, familyPackages) {
1515
1838
  const appRootDir = sys.getCurrentDirectory();
1516
1839
  const yarnLock = sys.readFileSync(sys.resolvePath(appRootDir + '/yarn.lock'));
1517
1840
  const yarnLockYml = sys.parseYarnLockFile(yarnLock);
1518
- return navifyPackages.map(([k, v]) => {
1841
+ return familyPackages.map(([k, v]) => {
1519
1842
  var _a;
1520
1843
  const identifiedVersion = `${k}@${v}`;
1521
1844
  let version = (_a = yarnLockYml.object[identifiedVersion]) === null || _a === void 0 ? void 0 : _a.version;
@@ -1580,7 +1903,7 @@ async function sendTelemetry(sys, config, data) {
1580
1903
  sent_at: now,
1581
1904
  };
1582
1905
  // This request is only made if telemetry is on.
1583
- const response = await sys.fetch('https://api-navifyjs.web.app/events/metrics', {
1906
+ const response = await sys.fetch('https://familyjs-api.web.app/events/metrics', {
1584
1907
  method: 'POST',
1585
1908
  headers: {
1586
1909
  'Content-Type': 'application/json',
@@ -1683,13 +2006,6 @@ const taskDocs = async (coreCompiler, config) => {
1683
2006
  await compiler.destroy();
1684
2007
  };
1685
2008
 
1686
- const IS_NODE_ENV = typeof global !== 'undefined' &&
1687
- typeof require === 'function' &&
1688
- !!global.process &&
1689
- typeof __filename === 'string' &&
1690
- (!global.origin || typeof global.origin !== 'string');
1691
- const IS_BROWSER_ENV = typeof location !== 'undefined' && typeof navigator !== 'undefined' && typeof XMLHttpRequest !== 'undefined';
1692
-
1693
2009
  /**
1694
2010
  * Task to generate component boilerplate and write it to disk. This task can
1695
2011
  * cause the program to exit with an error under various circumstances, such as
@@ -1718,13 +2034,24 @@ const taskGenerate = async (coreCompiler, config) => {
1718
2034
  const { prompt } = await import('../sys/node/prompts.js');
1719
2035
  const input = config.flags.unknownArgs.find((arg) => !arg.startsWith('-')) ||
1720
2036
  (await prompt({ name: 'tagName', type: 'text', message: 'Component tag name (dash-case):' })).tagName;
2037
+ if (undefined === input) {
2038
+ // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
2039
+ // explicitly return here to avoid printing the error message.
2040
+ return;
2041
+ }
1721
2042
  const { dir, base: componentName } = path.parse(input);
1722
2043
  const tagError = validateComponentTag(componentName);
1723
2044
  if (tagError) {
1724
2045
  config.logger.error(tagError);
1725
2046
  return config.sys.exit(1);
1726
2047
  }
1727
- const extensionsToGenerate = ['tsx', ...(await chooseFilesToGenerate())];
2048
+ const filesToGenerateExt = await chooseFilesToGenerate();
2049
+ if (undefined === filesToGenerateExt) {
2050
+ // in some shells (e.g. Windows PowerShell), hitting Ctrl+C results in a TypeError printed to the console.
2051
+ // explicitly return here to avoid printing the error message.
2052
+ return;
2053
+ }
2054
+ const extensionsToGenerate = ['tsx', ...filesToGenerateExt];
1728
2055
  const testFolder = extensionsToGenerate.some(isTest) ? 'test' : '';
1729
2056
  const outDir = path.join(absoluteSrcDir, 'components', dir, componentName);
1730
2057
  await config.sys.createDir(path.join(outDir, testFolder), { recursive: true });
@@ -1948,7 +2275,7 @@ const taskTelemetry = async (flags, sys, logger) => {
1948
2275
  const prompt = logger.dim(sys.details.platform === 'windows' ? '>' : '$');
1949
2276
  const isEnabling = flags.args.includes('on');
1950
2277
  const isDisabling = flags.args.includes('off');
1951
- const INFORMATION = `Opt in or our of telemetry. Information about the data we collect is available on our website: ${logger.bold('https://rindojs.web.app/telemetry')}`;
2278
+ const INFORMATION = `Opt in or out of telemetry. Information about the data we collect is available on our website: ${logger.bold('https://rindojs.web.app/telemetry')}`;
1952
2279
  const THANK_YOU = `Thank you for helping to make Rindo better! 💖`;
1953
2280
  const ENABLED_MESSAGE = `${logger.green('Enabled')}. ${THANK_YOU}\n\n`;
1954
2281
  const DISABLED_MESSAGE = `${logger.red('Disabled')}\n\n`;
@@ -2071,93 +2398,54 @@ const taskServe = async (config) => {
2071
2398
  };
2072
2399
 
2073
2400
  /**
2074
- * Creates an instance of a logger
2075
- * @returns the new logger instance
2401
+ * Entrypoint for any Rindo tests
2402
+ * @param config a validated Rindo configuration entity
2076
2403
  */
2077
- const createLogger = () => {
2078
- let useColors = IS_BROWSER_ENV;
2079
- let level = 'info';
2080
- return {
2081
- enableColors: (uc) => (useColors = uc),
2082
- getLevel: () => level,
2083
- setLevel: (l) => (level = l),
2084
- emoji: (e) => e,
2085
- info: console.log.bind(console),
2086
- warn: console.warn.bind(console),
2087
- error: console.error.bind(console),
2088
- debug: console.debug.bind(console),
2089
- red: (msg) => msg,
2090
- green: (msg) => msg,
2091
- yellow: (msg) => msg,
2092
- blue: (msg) => msg,
2093
- magenta: (msg) => msg,
2094
- cyan: (msg) => msg,
2095
- gray: (msg) => msg,
2096
- bold: (msg) => msg,
2097
- dim: (msg) => msg,
2098
- bgRed: (msg) => msg,
2099
- createTimeSpan: (_startMsg, _debug = false) => ({
2100
- duration: () => 0,
2101
- finish: () => 0,
2102
- }),
2103
- printDiagnostics(diagnostics) {
2104
- diagnostics.forEach((diagnostic) => logDiagnostic(diagnostic, useColors));
2105
- },
2106
- };
2107
- };
2108
- const logDiagnostic = (diagnostic, useColors) => {
2109
- let color = BLUE;
2110
- let prefix = 'Build';
2111
- let msg = '';
2112
- if (diagnostic.level === 'error') {
2113
- color = RED;
2114
- prefix = 'Error';
2115
- }
2116
- else if (diagnostic.level === 'warn') {
2117
- color = YELLOW;
2118
- prefix = 'Warning';
2119
- }
2120
- if (diagnostic.header) {
2121
- prefix = diagnostic.header;
2404
+ const taskTest = async (config) => {
2405
+ if (!IS_NODE_ENV) {
2406
+ config.logger.error(`"test" command is currently only implemented for a NodeJS environment`);
2407
+ return config.sys.exit(1);
2122
2408
  }
2123
- const filePath = diagnostic.relFilePath || diagnostic.absFilePath;
2124
- if (filePath) {
2125
- msg += filePath;
2126
- if (typeof diagnostic.lineNumber === 'number' && diagnostic.lineNumber > 0) {
2127
- msg += ', line ' + diagnostic.lineNumber;
2128
- if (typeof diagnostic.columnNumber === 'number' && diagnostic.columnNumber > 0) {
2129
- msg += ', column ' + diagnostic.columnNumber;
2130
- }
2409
+ config.buildDocs = false;
2410
+ const testingRunOpts = {
2411
+ e2e: !!config.flags.e2e,
2412
+ screenshot: !!config.flags.screenshot,
2413
+ spec: !!config.flags.spec,
2414
+ updateScreenshot: !!config.flags.updateScreenshot,
2415
+ };
2416
+ // always ensure we have jest modules installed
2417
+ const ensureModuleIds = ['@types/jest', 'jest', 'jest-cli'];
2418
+ if (testingRunOpts.e2e) {
2419
+ // if it's an e2e test, also make sure we're got
2420
+ // puppeteer modules installed and if browserExecutablePath is provided don't download Chromium use only puppeteer-core instead
2421
+ const puppeteer = config.testing.browserExecutablePath ? 'puppeteer-core' : 'puppeteer';
2422
+ ensureModuleIds.push(puppeteer);
2423
+ if (testingRunOpts.screenshot) {
2424
+ // ensure we've got pixelmatch for screenshots
2425
+ config.logger.warn(config.logger.yellow(`EXPERIMENTAL: screenshot visual diff testing is currently under heavy development and has not reached a stable status. However, any assistance testing would be appreciated.`));
2131
2426
  }
2132
- msg += '\n';
2133
- }
2134
- msg += diagnostic.messageText;
2135
- if (diagnostic.lines && diagnostic.lines.length > 0) {
2136
- diagnostic.lines.forEach((l) => {
2137
- msg += '\n' + l.lineNumber + ': ' + l.text;
2138
- });
2139
- msg += '\n';
2140
2427
  }
2141
- if (useColors) {
2142
- const styledPrefix = [
2143
- '%c' + prefix,
2144
- `background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`,
2145
- ];
2146
- console.log(...styledPrefix, msg);
2147
- }
2148
- else if (diagnostic.level === 'error') {
2149
- console.error(msg);
2428
+ // ensure we've got the required modules installed
2429
+ const diagnostics = await config.sys.lazyRequire.ensure(config.rootDir, ensureModuleIds);
2430
+ if (diagnostics.length > 0) {
2431
+ config.logger.printDiagnostics(diagnostics);
2432
+ return config.sys.exit(1);
2150
2433
  }
2151
- else if (diagnostic.level === 'warn') {
2152
- console.warn(msg);
2434
+ try {
2435
+ // let's test!
2436
+ const { createTesting } = await import('../testing/index.js');
2437
+ const testing = await createTesting(config);
2438
+ const passed = await testing.run(testingRunOpts);
2439
+ await testing.destroy();
2440
+ if (!passed) {
2441
+ return config.sys.exit(1);
2442
+ }
2153
2443
  }
2154
- else {
2155
- console.log(msg);
2444
+ catch (e) {
2445
+ config.logger.error(e);
2446
+ return config.sys.exit(1);
2156
2447
  }
2157
- };
2158
- const YELLOW = `#f39c12`;
2159
- const RED = `#c0392b`;
2160
- const BLUE = `#3498db`;
2448
+ };
2161
2449
 
2162
2450
  const run = async (init) => {
2163
2451
  const { args, logger, sys } = init;
@@ -2173,7 +2461,7 @@ const run = async (init) => {
2173
2461
  if (isFunction(sys.applyGlobalPatch)) {
2174
2462
  sys.applyGlobalPatch(sys.getCurrentDirectory());
2175
2463
  }
2176
- if (task === 'help' || flags.help) {
2464
+ if (!task || task === 'help' || flags.help) {
2177
2465
  await taskHelp(createConfigFlags({ task: 'help', args }), logger, sys);
2178
2466
  return;
2179
2467
  }
@@ -2242,15 +2530,16 @@ const run = async (init) => {
2242
2530
  * @public
2243
2531
  */
2244
2532
  const runTask = async (coreCompiler, config, task, sys) => {
2245
- var _a, _b, _c, _d, _e;
2533
+ var _a, _b, _c, _d, _e, _f;
2246
2534
  const logger = (_a = config.logger) !== null && _a !== void 0 ? _a : createLogger();
2247
2535
  const strictConfig = {
2248
2536
  ...config,
2249
2537
  flags: createConfigFlags((_b = config.flags) !== null && _b !== void 0 ? _b : { task }),
2250
2538
  logger,
2251
2539
  outputTargets: (_c = config.outputTargets) !== null && _c !== void 0 ? _c : [],
2252
- sys: (_d = sys !== null && sys !== void 0 ? sys : config.sys) !== null && _d !== void 0 ? _d : coreCompiler.createSystem({ logger }),
2253
- testing: (_e = config.testing) !== null && _e !== void 0 ? _e : {},
2540
+ rootDir: (_d = config.rootDir) !== null && _d !== void 0 ? _d : '/',
2541
+ sys: (_e = sys !== null && sys !== void 0 ? sys : config.sys) !== null && _e !== void 0 ? _e : coreCompiler.createSystem({ logger }),
2542
+ testing: (_f = config.testing) !== null && _f !== void 0 ? _f : {},
2254
2543
  };
2255
2544
  switch (task) {
2256
2545
  case 'build':
@@ -2275,6 +2564,9 @@ const runTask = async (coreCompiler, config, task, sys) => {
2275
2564
  case 'telemetry':
2276
2565
  await taskTelemetry(strictConfig.flags, sys, strictConfig.logger);
2277
2566
  break;
2567
+ case 'test':
2568
+ await taskTest(strictConfig);
2569
+ break;
2278
2570
  case 'version':
2279
2571
  console.log(coreCompiler.version);
2280
2572
  break;