|
1 | 1 | import fs from 'node:fs'; |
2 | 2 | import { AppError } from '../../utils/errors.ts'; |
3 | 3 | import type { PlatformSelector } from '../../utils/device.ts'; |
4 | | -import { appendOpenActionScriptArgs, parseReplayOpenFlags } from '../session-open-script.ts'; |
| 4 | +import { parseReplayOpenFlags } from '../session-open-script.ts'; |
| 5 | +import { formatPortableActionLine } from '../session-script-formatting.ts'; |
5 | 6 | import type { SessionAction, SessionState } from '../types.ts'; |
6 | 7 | import { |
7 | | - appendRecordActionScriptArgs, |
8 | | - appendRuntimeHintFlags, |
9 | | - appendScriptSeriesFlags, |
10 | | - formatScriptArgQuoteIfNeeded, |
11 | | - formatScriptArg, |
12 | 8 | formatScriptStringLiteral, |
13 | 9 | isClickLikeCommand, |
14 | 10 | parseReplaySeriesFlags, |
@@ -381,36 +377,57 @@ function tokenizeReplayLine(line: string): string[] { |
381 | 377 | const tokens: string[] = []; |
382 | 378 | let cursor = 0; |
383 | 379 | while (cursor < line.length) { |
384 | | - while (cursor < line.length && /\s/.test(line[cursor])) { |
385 | | - cursor += 1; |
386 | | - } |
| 380 | + cursor = skipReplayWhitespace(line, cursor); |
387 | 381 | if (cursor >= line.length) break; |
388 | | - if (line[cursor] === '"') { |
389 | | - let end = cursor + 1; |
390 | | - let escaped = false; |
391 | | - while (end < line.length) { |
392 | | - const char = line[end]; |
393 | | - if (char === '"' && !escaped) break; |
394 | | - escaped = char === '\\' && !escaped; |
395 | | - if (char !== '\\') escaped = false; |
396 | | - end += 1; |
397 | | - } |
398 | | - if (end >= line.length) { |
399 | | - throw new AppError('INVALID_ARGS', `Invalid replay script line: ${line}`); |
400 | | - } |
401 | | - const literal = line.slice(cursor, end + 1); |
402 | | - tokens.push(JSON.parse(literal) as string); |
403 | | - cursor = end + 1; |
| 382 | + const parsed = |
| 383 | + line[cursor] === '"' |
| 384 | + ? readQuotedReplayToken(line, cursor) |
| 385 | + : readBareReplayToken(line, cursor); |
| 386 | + tokens.push(parsed.value); |
| 387 | + cursor = parsed.nextCursor; |
| 388 | + } |
| 389 | + return tokens; |
| 390 | +} |
| 391 | + |
| 392 | +function skipReplayWhitespace(line: string, cursor: number): number { |
| 393 | + let nextCursor = cursor; |
| 394 | + while (nextCursor < line.length && /\s/.test(line[nextCursor])) { |
| 395 | + nextCursor += 1; |
| 396 | + } |
| 397 | + return nextCursor; |
| 398 | +} |
| 399 | + |
| 400 | +function readQuotedReplayToken( |
| 401 | + line: string, |
| 402 | + cursor: number, |
| 403 | +): { value: string; nextCursor: number } { |
| 404 | + const tokenStart = cursor + 1; |
| 405 | + let escaped = false; |
| 406 | + let end = tokenStart; |
| 407 | + for (; end < line.length; end += 1) { |
| 408 | + const char = line[end]; |
| 409 | + if (char === '"' && !escaped) break; |
| 410 | + if (escaped) { |
| 411 | + escaped = false; |
404 | 412 | continue; |
405 | 413 | } |
406 | | - let end = cursor; |
407 | | - while (end < line.length && !/\s/.test(line[end])) { |
408 | | - end += 1; |
409 | | - } |
410 | | - tokens.push(line.slice(cursor, end)); |
411 | | - cursor = end; |
| 414 | + escaped = char === '\\'; |
412 | 415 | } |
413 | | - return tokens; |
| 416 | + if (end >= line.length) { |
| 417 | + throw new AppError('INVALID_ARGS', `Invalid replay script line: ${line}`); |
| 418 | + } |
| 419 | + return { |
| 420 | + value: JSON.parse(line.slice(cursor, end + 1)) as string, |
| 421 | + nextCursor: end + 1, |
| 422 | + }; |
| 423 | +} |
| 424 | + |
| 425 | +function readBareReplayToken(line: string, cursor: number): { value: string; nextCursor: number } { |
| 426 | + let end = cursor; |
| 427 | + while (end < line.length && !/\s/.test(line[end])) { |
| 428 | + end += 1; |
| 429 | + } |
| 430 | + return { value: line.slice(cursor, end), nextCursor: end }; |
414 | 431 | } |
415 | 432 |
|
416 | 433 | export function writeReplayScript( |
@@ -438,47 +455,5 @@ export function writeReplayScript( |
438 | 455 | } |
439 | 456 |
|
440 | 457 | function formatReplayActionLine(action: SessionAction): string { |
441 | | - const parts: string[] = [action.command]; |
442 | | - if (action.command === 'snapshot') { |
443 | | - if (action.flags?.snapshotInteractiveOnly) parts.push('-i'); |
444 | | - if (action.flags?.snapshotCompact) parts.push('-c'); |
445 | | - if (typeof action.flags?.snapshotDepth === 'number') { |
446 | | - parts.push('-d', String(action.flags.snapshotDepth)); |
447 | | - } |
448 | | - if (action.flags?.snapshotScope) { |
449 | | - parts.push('-s', formatScriptArg(action.flags.snapshotScope)); |
450 | | - } |
451 | | - if (action.flags?.snapshotRaw) parts.push('--raw'); |
452 | | - return parts.join(' '); |
453 | | - } |
454 | | - if (action.command === 'open') { |
455 | | - appendOpenActionScriptArgs(parts, action); |
456 | | - return parts.join(' '); |
457 | | - } |
458 | | - if (action.command === 'runtime') { |
459 | | - for (const positional of action.positionals ?? []) { |
460 | | - parts.push(formatScriptArgQuoteIfNeeded(positional)); |
461 | | - } |
462 | | - appendRuntimeHintFlags(parts, action.flags); |
463 | | - return parts.join(' '); |
464 | | - } |
465 | | - if (action.command === 'record') { |
466 | | - appendRecordActionScriptArgs(parts, action); |
467 | | - return parts.join(' '); |
468 | | - } |
469 | | - if (action.command === 'screenshot') { |
470 | | - for (const positional of action.positionals ?? []) { |
471 | | - parts.push(formatScriptArg(positional)); |
472 | | - } |
473 | | - if (action.flags?.screenshotFullscreen) parts.push('--fullscreen'); |
474 | | - if (typeof action.flags?.screenshotMaxSize === 'number') { |
475 | | - parts.push('--max-size', String(action.flags.screenshotMaxSize)); |
476 | | - } |
477 | | - return parts.join(' '); |
478 | | - } |
479 | | - for (const positional of action.positionals ?? []) { |
480 | | - parts.push(formatScriptArg(positional)); |
481 | | - } |
482 | | - appendScriptSeriesFlags(parts, action); |
483 | | - return parts.join(' '); |
| 458 | + return formatPortableActionLine(action, { runtimeIncludeAllPositionals: true }); |
484 | 459 | } |
0 commit comments