@enactprotocol/shared 2.0.5 → 2.0.6

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.
@@ -11,6 +11,7 @@ import {
11
11
  prepareCommand,
12
12
  shellEscape,
13
13
  } from "../../src/execution/command";
14
+ import type { CommandWarning } from "../../src/execution/types";
14
15
 
15
16
  describe("Command Interpolation", () => {
16
17
  describe("parseCommand", () => {
@@ -69,6 +70,63 @@ describe("Command Interpolation", () => {
69
70
 
70
71
  expect(result.parameters).toEqual(["name"]);
71
72
  });
73
+
74
+ test("parses :raw modifier", () => {
75
+ const result = parseCommand("echo ${data:raw}");
76
+
77
+ expect(result.parameters).toEqual(["data"]);
78
+ expect(result.tokens).toHaveLength(2);
79
+ expect(result.tokens[1]).toEqual({ type: "parameter", name: "data", raw: true });
80
+ });
81
+
82
+ test("detects single-quoted parameter", () => {
83
+ const result = parseCommand("echo '${message}'");
84
+
85
+ expect(result.tokens).toHaveLength(2);
86
+ expect(result.tokens[0]).toEqual({ type: "literal", value: "echo " });
87
+ expect(result.tokens[1]).toEqual({
88
+ type: "parameter",
89
+ name: "message",
90
+ surroundingQuotes: "single",
91
+ });
92
+ });
93
+
94
+ test("detects double-quoted parameter", () => {
95
+ const result = parseCommand('echo "${message}"');
96
+
97
+ expect(result.tokens).toHaveLength(2);
98
+ expect(result.tokens[1]).toEqual({
99
+ type: "parameter",
100
+ name: "message",
101
+ surroundingQuotes: "double",
102
+ });
103
+ });
104
+
105
+ test("handles mix of quoted and unquoted parameters", () => {
106
+ const result = parseCommand("cmd '${a}' ${b} \"${c}\"");
107
+
108
+ expect(result.parameters).toEqual(["a", "b", "c"]);
109
+ expect(result.tokens[1]).toMatchObject({ name: "a", surroundingQuotes: "single" });
110
+ expect(result.tokens[3]).toMatchObject({ name: "b" });
111
+ expect(
112
+ (result.tokens[3] as { surroundingQuotes?: string }).surroundingQuotes
113
+ ).toBeUndefined();
114
+ expect(result.tokens[5]).toMatchObject({ name: "c", surroundingQuotes: "double" });
115
+ });
116
+
117
+ test("does not detect quotes that don't surround the parameter", () => {
118
+ // Single quote before but not after
119
+ const result1 = parseCommand("echo '${a} foo");
120
+ expect(
121
+ (result1.tokens[1] as { surroundingQuotes?: string }).surroundingQuotes
122
+ ).toBeUndefined();
123
+
124
+ // Mismatched quotes
125
+ const result2 = parseCommand("echo '${a}\"");
126
+ expect(
127
+ (result2.tokens[1] as { surroundingQuotes?: string }).surroundingQuotes
128
+ ).toBeUndefined();
129
+ });
72
130
  });
73
131
 
74
132
  describe("interpolateCommand", () => {
@@ -154,6 +212,103 @@ describe("Command Interpolation", () => {
154
212
 
155
213
  expect(result).toBe("echo [1,2,3]");
156
214
  });
215
+
216
+ test("handles :raw modifier - no escaping", () => {
217
+ const result = interpolateCommand("echo ${data:raw}", {
218
+ data: "hello world",
219
+ });
220
+
221
+ // Without :raw, "hello world" would become 'hello world' (quoted)
222
+ // With :raw, it stays as-is
223
+ expect(result).toBe("echo hello world");
224
+ });
225
+
226
+ test("handles :raw modifier with JSON", () => {
227
+ const result = interpolateCommand("echo ${json:raw}", {
228
+ json: { key: "value" },
229
+ });
230
+
231
+ // JSON is stringified but not quoted
232
+ expect(result).toBe('echo {"key":"value"}');
233
+ });
234
+
235
+ test("strips surrounding single quotes and applies proper escaping", () => {
236
+ // This is the key fix for the double-quoting issue
237
+ const result = interpolateCommand("node script.js '${input}'", {
238
+ input: '[{"name":"Alice"}]',
239
+ });
240
+
241
+ // The surrounding quotes are stripped, and the value is properly escaped
242
+ // JSON with special chars gets single-quoted by shellEscape
243
+ expect(result).toBe('node script.js \'[{"name":"Alice"}]\'');
244
+ });
245
+
246
+ test("strips surrounding double quotes and applies proper escaping", () => {
247
+ const result = interpolateCommand('node script.js "${input}"', {
248
+ input: "hello world",
249
+ });
250
+
251
+ // The surrounding quotes are stripped, value gets quoted by shellEscape
252
+ expect(result).toBe("node script.js 'hello world'");
253
+ });
254
+
255
+ test("emits warning when stripping surrounding quotes", () => {
256
+ const warnings: CommandWarning[] = [];
257
+
258
+ interpolateCommand(
259
+ "echo '${message}'",
260
+ { message: "test" },
261
+ {
262
+ onWarning: (w) => warnings.push(w),
263
+ }
264
+ );
265
+
266
+ expect(warnings).toHaveLength(1);
267
+ expect(warnings[0]?.code).toBe("DOUBLE_QUOTING");
268
+ expect(warnings[0]?.parameter).toBe("message");
269
+ expect(warnings[0]?.suggestion).toContain("${message}");
270
+ });
271
+
272
+ test("no warning for unquoted parameters", () => {
273
+ const warnings: CommandWarning[] = [];
274
+
275
+ interpolateCommand(
276
+ "echo ${message}",
277
+ { message: "test" },
278
+ {
279
+ onWarning: (w) => warnings.push(w),
280
+ }
281
+ );
282
+
283
+ expect(warnings).toHaveLength(0);
284
+ });
285
+
286
+ test("handles complex JSON input without double-quoting", () => {
287
+ // This is the exact case from the user's feedback
288
+ const result = interpolateCommand(
289
+ "node dist/index.js ${input} ${input_format} ${output_format}",
290
+ {
291
+ input: '[{"name":"Alice"}]',
292
+ input_format: "json",
293
+ output_format: "csv",
294
+ }
295
+ );
296
+
297
+ // JSON gets quoted, simple strings don't
298
+ expect(result).toBe('node dist/index.js \'[{"name":"Alice"}]\' json csv');
299
+ });
300
+
301
+ test("handles quoted parameter template that would have caused double-quoting", () => {
302
+ // Without the fix, this would produce: node dist/index.js ''[{"name":"Alice"}]''
303
+ // With the fix, surrounding quotes are stripped first
304
+ const result = interpolateCommand("node dist/index.js '${input}'", {
305
+ input: '[{"name":"Alice"}]',
306
+ });
307
+
308
+ // Should NOT have double quotes
309
+ expect(result).not.toContain("''");
310
+ expect(result).toBe('node dist/index.js \'[{"name":"Alice"}]\'');
311
+ });
157
312
  });
158
313
 
159
314
  describe("shellEscape", () => {