From c9f41c2905cd5b1f638b36a209e097f66e59cfde Mon Sep 17 00:00:00 2001 From: garrettmills Date: Thu, 5 Mar 2026 10:09:26 -0600 Subject: [PATCH] Add new restructureOrLines match target + update join command to use it --- src/vm/commands/command.ts | 9 +++++++++ src/vm/commands/join.ts | 2 +- src/vm/vm.ts | 28 +++++++++++++++++----------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/vm/commands/command.ts b/src/vm/commands/command.ts index e54f3f7..c73a8d2 100644 --- a/src/vm/commands/command.ts +++ b/src/vm/commands/command.ts @@ -26,6 +26,15 @@ export const joinDestructured = (val: StrDestructured['value']): string => .map(part => `${part.prefix || ''}${part.value}`) .join('') +export const destructureToLines = (val: string): StrDestructured['value'] => val + .split('\n') + .map((line, idx) => { + if ( idx ) { + return { prefix: '\n', value: line } + } + return { value: line } + }) + export type StrRVal = { term: 'string', value: string, literal?: true } | { term: 'int', value: number } diff --git a/src/vm/commands/join.ts b/src/vm/commands/join.ts index df39773..c3ced29 100644 --- a/src/vm/commands/join.ts +++ b/src/vm/commands/join.ts @@ -20,7 +20,7 @@ export class Join extends Command<{ with?: StrTerm }> { execute(vm: StrVM, data: { with?: StrTerm }): Awaitable { return vm.replaceContextMatchingTerm(ctx => ({ - restructure: parts => { + restructureOrLines: parts => { if ( data.with ) { return parts .map(part => part.value) diff --git a/src/vm/vm.ts b/src/vm/vm.ts index 2540c72..47e35ce 100644 --- a/src/vm/vm.ts +++ b/src/vm/vm.ts @@ -1,6 +1,6 @@ import {Awaitable, JSONData} from "../util/types.js"; import { - CommandData, + CommandData, destructureToLines, isStrRVal, joinDestructured, StrDestructured, StrLVal, StrRVal, @@ -77,6 +77,11 @@ export type TermOperator = { string?: string | ((sub: string) => Awaitable), /** Map `destructured` to `string`. */ restructure?: (sub: StrDestructured['value']) => Awaitable, + /** + * If `string`, destructure to lines, then map. + * If `destructured`, map directly. + */ + restructureOrLines?: (sub: StrDestructured['value']) => Awaitable, /** Map `destructured` to `destructured`. */ destructured?: (sub: StrDestructured['value']) => Awaitable, /** @@ -180,22 +185,18 @@ export class ExecutionContext { return } + if ( (sub.term === 'int' || sub.term === 'string') && operator.restructureOrLines ) { + this.subject = wrapString(await operator.restructureOrLines(destructureToLines(unwrapString(sub)))) + return + } + if ( (sub.term === 'int' || sub.term === 'string') && operator.stringOrDestructuredPart ) { this.subject = wrapString(await operator.stringOrDestructuredPart(unwrapString(sub))) return } if ( (sub.term === 'int' || sub.term === 'string') && operator.destructuredOrLines ) { - const fake: StrDestructured['value'] = unwrapString(sub) - .split('\n') - .map((line, idx) => { - if ( idx ) { - return { prefix: '\n', value: line } - } - return { value: line } - }) - - const rejoined = (await operator.destructuredOrLines(fake)) + const rejoined = (await operator.destructuredOrLines(destructureToLines(unwrapString(sub)))) .map(x => x.value) .join('\n') @@ -208,6 +209,11 @@ export class ExecutionContext { return } + if ( sub.term === 'destructured' && operator.restructureOrLines ) { + this.subject = wrapString(await operator.restructureOrLines(unwrapDestructured(sub))) + return + } + if ( sub.term === 'destructured' && operator.destructured ) { this.subject = wrapDestructured(await operator.destructured(unwrapDestructured(sub))) return