@enactprotocol/shared 2.1.21 → 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.
- package/dist/execution/command.d.ts +38 -4
- package/dist/execution/command.d.ts.map +1 -1
- package/dist/execution/command.js +42 -8
- package/dist/execution/command.js.map +1 -1
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/types.d.ts +6 -0
- package/dist/execution/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/execution/command.ts +58 -7
- package/src/execution/index.ts +1 -0
- package/src/execution/types.ts +6 -0
- package/tests/execution/command.test.ts +231 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -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" });
|