ek9_rewrite_string_concat

Replaces a selected `"a" + var + "b"` concat with the equivalent backtick interpolation, escaping backtick and `$` in literal segments; answers status and edits[] (one REPLACE), conflicts[] (selection-not-a-string-expression, operand-has-no-string-operator with a suggestedRepair), or status:unchanged when the selection is already a backtick literal.

Category: Editor · Compare: IntelliJ "Convert to template string" / VS Code "Convert to template literal"

When to use it

'Turn this "a" + var + "b" concat into a backtick literal' is one call with file and selection:{startLine, startColumn, endLine, endColumn} (1-based, inclusive) covering exactly the concat expression. Use it when a concat reads better interpolated, or before ek9_extract_to_localized_text.

When not to use it

Details

Transformation is syntactic; the admission gate is semantic - a compiled program is required and every operand's type must define `_string()`, else a conflict carrying a suggestedRepair. A selection already in target form is status:unchanged (nothing written). Escaping: backtick and `$` in literal segments are escaped; redundant \" is reduced to "; \n \t \r \\ preserved verbatim.

Arguments

ArgumentTypeRequiredWhat it is
filestringyesWorkspace-relative path to the .ek9 source file containing the selection.
selectionobjectyesThe IDE selection covering exactly the concat expression (or one string literal): startLine/endLine and startColumn/endColumn, all 1-based, end INCLUSIVE - read them off ek9_read_file(lineNumbers:true). startCol/endCol are accepted.

It also takes the arguments every tool takes.

Recorded calls

Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 7 recorded are shown.

Already in target form

Request

{
  "selection" : {
    "endCol" : 33,
    "endLine" : 8,
    "startCol" : 19,
    "startLine" : 8
  },
  "targetFile" : "Hello.ek9"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "risk" : {
    "crossesModuleBoundary" : false,
    "estimatedSeverity" : "trivial",
    "fileCount" : 0,
    "lineCount" : 0,
    "touchesPublicApi" : false,
    "touchesTests" : false
  },
  "status" : "unchanged",
  "summary" : "Selection is already a backtick literal - nothing to rewrite",
  "workspaceHash" : "<workspace-hash>",
  "wouldBeDiagnostics" : [ ],
  "written" : false
}

Simple concat dry run

Request

{
  "dryRun" : true,
  "selection" : {
    "endCol" : 33,
    "endLine" : 8,
    "startCol" : 19,
    "startLine" : 8
  },
  "targetFile" : "Greeter.ek9"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ {
    "after" : "`Hello ${name}`",
    "before" : "\"Hello \" + name",
    "endLine" : 8,
    "file" : "Greeter.ek9",
    "startLine" : 8,
    "type" : "replace"
  } ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "risk" : {
    "crossesModuleBoundary" : false,
    "estimatedSeverity" : "trivial",
    "fileCount" : 1,
    "lineCount" : 1,
    "touchesPublicApi" : false,
    "touchesTests" : false
  },
  "status" : "ready",
  "summary" : "Would rewrite 2-operand concat to backtick interpolation with 1 substitution",
  "workspaceHash" : "<workspace-hash>",
...

Cut short here: 3 more lines. The whole recorded call.

Conflict misaligned selection

Request

{
  "selection" : {
    "endCol" : 28,
    "endLine" : 8,
    "startCol" : 19,
    "startLine" : 8
  },
  "targetFile" : "Greeter.ek9"
}

Response

{
  "conflicts" : [ {
    "kind" : "selection-not-a-string-expression",
    "reason" : "Selection does not span a parseable string expression — expand the selection to cover exactly the concat or literal."
  } ],
  "edits" : [ ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "risk" : {
    "crossesModuleBoundary" : false,
    "estimatedSeverity" : "trivial",
    "fileCount" : 0,
    "lineCount" : 0,
    "touchesPublicApi" : false,
    "touchesTests" : false
  },
  "status" : "conflicts",
  "summary" : "Cannot rewrite: selection-not-a-string-expression",
  "workspaceHash" : "<workspace-hash>",
  "wouldBeDiagnostics" : [ ],
  "written" : false
}

See also