@enactprotocol/shared 2.1.22 → 2.1.23

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.
@@ -431,6 +431,237 @@ describe("Command Interpolation", () => {
431
431
  });
432
432
  });
433
433
 
434
+ describe("knownParameters filtering", () => {
435
+ describe("parseCommand with knownParameters", () => {
436
+ test("only treats known parameters as parameters", () => {
437
+ const result = parseCommand("echo ${name} and ${unknown}", {
438
+ knownParameters: new Set(["name"]),
439
+ });
440
+
441
+ expect(result.parameters).toEqual(["name"]);
442
+ expect(result.tokens).toHaveLength(3);
443
+ expect(result.tokens[0]).toEqual({ type: "literal", value: "echo " });
444
+ expect(result.tokens[1]).toEqual({ type: "parameter", name: "name" });
445
+ expect(result.tokens[2]).toEqual({ type: "literal", value: " and ${unknown}" });
446
+ });
447
+
448
+ test("preserves bash array syntax ${#array[@]}", () => {
449
+ const result = parseCommand("echo ${#compliments[@]}", {
450
+ knownParameters: new Set(["name"]),
451
+ });
452
+
453
+ // The entire string should be a literal since #compliments[@] is not a known param
454
+ expect(result.parameters).toEqual([]);
455
+ expect(result.tokens).toHaveLength(1);
456
+ expect(result.tokens[0]).toEqual({
457
+ type: "literal",
458
+ value: "echo ${#compliments[@]}",
459
+ });
460
+ });
461
+
462
+ test("preserves bash array indexing ${array[$i]}", () => {
463
+ const result = parseCommand('echo "${compliments[$random_index]}"', {
464
+ knownParameters: new Set(["name"]),
465
+ });
466
+
467
+ expect(result.parameters).toEqual([]);
468
+ expect(result.tokens).toHaveLength(1);
469
+ expect(result.tokens[0]).toEqual({
470
+ type: "literal",
471
+ value: 'echo "${compliments[$random_index]}"',
472
+ });
473
+ });
474
+
475
+ test("handles mix of known params and bash syntax", () => {
476
+ const cmd = 'echo "${name}" and ${#arr[@]} and ${arr[$i]} and ${OTHER_VAR}';
477
+ const result = parseCommand(cmd, {
478
+ knownParameters: new Set(["name"]),
479
+ });
480
+
481
+ expect(result.parameters).toEqual(["name"]);
482
+ // Should have: literal, param, literal (containing all the bash stuff)
483
+ expect(result.tokens).toHaveLength(3);
484
+ expect(result.tokens[0]).toEqual({ type: "literal", value: "echo " });
485
+ expect(result.tokens[1]).toMatchObject({ type: "parameter", name: "name" });
486
+ expect(result.tokens[2]).toEqual({
487
+ type: "literal",
488
+ value: " and ${#arr[@]} and ${arr[$i]} and ${OTHER_VAR}",
489
+ });
490
+ });
491
+
492
+ test("legacy behavior when knownParameters not provided", () => {
493
+ const result = parseCommand("echo ${name} ${unknown}");
494
+
495
+ // Without knownParameters, all ${...} are treated as params
496
+ expect(result.parameters).toEqual(["name", "unknown"]);
497
+ });
498
+
499
+ test("empty knownParameters set treats nothing as parameter", () => {
500
+ const result = parseCommand("echo ${name} ${other}", {
501
+ knownParameters: new Set(),
502
+ });
503
+
504
+ expect(result.parameters).toEqual([]);
505
+ expect(result.tokens).toHaveLength(1);
506
+ expect(result.tokens[0]).toEqual({
507
+ type: "literal",
508
+ value: "echo ${name} ${other}",
509
+ });
510
+ });
511
+ });
512
+
513
+ describe("interpolateCommand with knownParameters", () => {
514
+ test("only substitutes known parameters", () => {
515
+ const result = interpolateCommand(
516
+ "echo ${name} and ${MY_VAR}",
517
+ { name: "Keith" },
518
+ { knownParameters: new Set(["name"]) }
519
+ );
520
+
521
+ expect(result).toBe("echo Keith and ${MY_VAR}");
522
+ });
523
+
524
+ test("preserves bash array operations", () => {
525
+ const cmd = 'arr=("a" "b"); echo ${#arr[@]} items: ${arr[0]}';
526
+ const result = interpolateCommand(
527
+ cmd,
528
+ {},
529
+ {
530
+ knownParameters: new Set(["name"]),
531
+ }
532
+ );
533
+
534
+ // Nothing should be substituted
535
+ expect(result).toBe(cmd);
536
+ });
537
+
538
+ test("substitutes only schema-defined params in complex command", () => {
539
+ const cmd = `
540
+ NAME="\${name}"
541
+ compliments=("Hello, $NAME!")
542
+ echo "\${compliments[0]}"
543
+ `;
544
+ const result = interpolateCommand(
545
+ cmd,
546
+ { name: "Alice" },
547
+ { knownParameters: new Set(["name"]) }
548
+ );
549
+
550
+ expect(result).toContain("Alice");
551
+ expect(result).toContain("${compliments[0]}");
552
+ });
553
+ });
554
+
555
+ describe("prepareCommand with knownParameters", () => {
556
+ test("passes through bash syntax while substituting known params", () => {
557
+ const result = prepareCommand(
558
+ "echo ${name} ${RANDOM}",
559
+ { name: "test" },
560
+ { knownParameters: new Set(["name"]) }
561
+ );
562
+
563
+ // Contains ${RANDOM} which has $, so needs shell wrap
564
+ expect(result).toEqual(["sh", "-c", "echo test ${RANDOM}"]);
565
+ });
566
+
567
+ test("handles full bash script with arrays", () => {
568
+ const cmd = `
569
+ arr=("\${name}" "b" "c")
570
+ echo \${#arr[@]}
571
+ echo \${arr[0]}
572
+ `;
573
+ const result = prepareCommand(
574
+ cmd,
575
+ { name: "Keith" },
576
+ {
577
+ knownParameters: new Set(["name"]),
578
+ }
579
+ );
580
+
581
+ // Should be shell wrapped due to special chars
582
+ expect(result[0]).toBe("sh");
583
+ expect(result[1]).toBe("-c");
584
+ // The name should be substituted but array syntax preserved
585
+ expect(result[2]).toContain("Keith");
586
+ expect(result[2]).toContain("${#arr[@]}");
587
+ expect(result[2]).toContain("${arr[0]}");
588
+ });
589
+ });
590
+
591
+ describe("getMissingParams with knownParameters", () => {
592
+ test("only checks known parameters", () => {
593
+ const result = getMissingParams(
594
+ "echo ${name} ${unknown}",
595
+ {},
596
+ { knownParameters: new Set(["name"]) }
597
+ );
598
+
599
+ // Only "name" is a known param, and it's missing
600
+ expect(result).toEqual(["name"]);
601
+ });
602
+
603
+ test("ignores unknown ${...} patterns", () => {
604
+ const result = getMissingParams(
605
+ "echo ${name} ${#arr[@]} ${arr[$i]}",
606
+ { name: "Keith" },
607
+ { knownParameters: new Set(["name"]) }
608
+ );
609
+
610
+ // name is provided, others are not params
611
+ expect(result).toEqual([]);
612
+ });
613
+ });
614
+
615
+ describe("real-world bash examples", () => {
616
+ test("compliment generator with bash arrays", () => {
617
+ const cmd = `
618
+ compliments=(
619
+ "You're great, \${name}!"
620
+ "Keep it up, \${name}!"
621
+ )
622
+ random_index=$((RANDOM % \${#compliments[@]}))
623
+ echo "\${compliments[$random_index]}"
624
+ `;
625
+ const result = interpolateCommand(
626
+ cmd,
627
+ { name: "Keith" },
628
+ { knownParameters: new Set(["name"]) }
629
+ );
630
+
631
+ // ${name} should be substituted
632
+ expect(result).toContain("You're great, Keith!");
633
+ expect(result).toContain("Keep it up, Keith!");
634
+ // Bash syntax should be preserved
635
+ expect(result).toContain("${#compliments[@]}");
636
+ expect(result).toContain("${compliments[$random_index]}");
637
+ });
638
+
639
+ test("script with environment variables", () => {
640
+ const cmd = 'echo "Hello ${name}, your home is ${HOME}"';
641
+ const result = interpolateCommand(
642
+ cmd,
643
+ { name: "Alice" },
644
+ { knownParameters: new Set(["name"]) }
645
+ );
646
+
647
+ expect(result).toBe('echo "Hello Alice, your home is ${HOME}"');
648
+ });
649
+
650
+ test("for loop with index variable", () => {
651
+ const cmd = 'for i in 1 2 3; do echo "${prefix}$i"; done';
652
+ const result = interpolateCommand(
653
+ cmd,
654
+ { prefix: "item-" },
655
+ { knownParameters: new Set(["prefix"]) }
656
+ );
657
+
658
+ // prefix substituted, $i preserved (though not in ${} form)
659
+ expect(result).toContain("item-");
660
+ expect(result).toContain("$i");
661
+ });
662
+ });
663
+ });
664
+
434
665
  describe("getMissingParams", () => {
435
666
  test("returns empty array when all params present", () => {
436
667
  const result = getMissingParams("echo ${a} ${b}", { a: "1", b: "2" });