Skip to content

Deprecate ${name} in favour of {{name}} (multi-phase migration) #145

@thomas-stegemann

Description

@thomas-stegemann

Why

After #125 v1 landed, Bowire has two interpolation syntaxes that resolve identically:

  • ${name} — Bowire's original Bash-style syntax (escape: $${name})
  • {{name}} — Postman / Mustache convention (escape: {{{{name}}}})

Two syntaxes for one operation is confusing — every doc reader, new operator, and recording author has to learn both. {{...}} won the design call because:

  • It matches Postman / Insomnia / Hoppscotch — every importer hits it for free
  • It composes cleanly with source prefixes ({{env.X}}, {{prev.X}}, {{step1.Y}})
  • Phase-2 features (autocomplete dropdown, color-coded chips, source picker) target it

${...} stays as a legacy alias only because every existing recording / collection / saved request uses it. We need a planned migration window before deprecation.

Plan

Phase 0 — Today

  • Both syntaxes work. Documentation + new examples should already prefer {{...}}.

Phase 1 — Soft deprecation

  • Add a one-time toast on workbench load when the active workspace's stored data contains ${...} placeholders: "This workspace uses the legacy ${name} syntax. The canonical syntax is {{name}}. Open Settings → Migration to convert."
  • New surfaces (Cmd+K palette, AI prompts, empty-state copy) only emit {{...}}.
  • Docs explicitly mark ${...} as legacy.

Phase 2 — Migration tool

  • Settings → Migration page or one-shot migration command.
  • Walks every recording, collection, environment, flow, freeform draft — rewrites ${name} to {{name}} (and ${response.X} to {{prev.X}}, ${now} to {{runtime.now}}, etc.).
  • Dry-run + diff view before commit. Per-workspace scope.
  • Disk-stored recordings get touched too.
  • Migration emits a single commit-style transition record so the workspace metadata says "migrated to {{}}-syntax at ".

Phase 3 — Hard deprecation

  • ${name} substitution stops resolving. Placeholders pass through literally (so the operator sees the typo).
  • One-line warning in the workbench console: "Legacy ${} interpolation is no longer resolved. Run Settings → Migration to convert."
  • Major-version bump.

Phase 4 — Removal

  • Parser drops the ${...} branch entirely. Next major version after Phase 3.

Migration script — concrete rewrites

From To
${NAME} {{NAME}}
${env.NAME} {{env.NAME}}
${response.path} {{prev.path}}
${response} {{prev}}
${now} / ${nowMs} / ${timestamp} {{runtime.now}} / {{runtime.nowMs}} / {{runtime.timestamp}}
${uuid} / ${random} {{runtime.uuid}} / {{runtime.random}}
${now+3600} {{runtime.now+3600}}
$${NAME} (literal escape) {{{{NAME}}}} (quadruple-brace escape)

The migration walks string-typed fields in:

  • recordingsList[].steps[].body / messages[] / metadata
  • collectionsList[].items[].body / headers / params
  • getEnvironments()[].vars[].value
  • flowsList[].nodes[].config.<various>
  • freeformRequest.body / serverUrl / metadata

Acceptance — per phase

Phase 1

Phase 2

  • Settings → Migration page with dry-run preview.
  • One-command migration via Bowire.Cli migrate-vars (for embedded / headless).
  • Per-workspace migration log persisted.
  • Migration is idempotent (re-running yields no diff).

Phase 3

  • ${...} no longer substitutes; renders literally.
  • Console warning on load when ${...} still present.
  • Release note documents the breaking change.

Phase 4

  • Parser branch removed.
  • One major version after Phase 3 ships.

Composes with

Out of scope

  • Auto-migration on first read of a recording. Too magical; operator must opt in via the migration tool.
  • Re-encoding ${...} to \\{...\\} or other escape forms. The canonical move is the syntactic swap, not a hybrid.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:workbenchUI / workbench surfaceroadmapTracked on the public Project board

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions