ek9_add_program

Appends the program (or @Test program) to the file's 'defines program' block, created if absent, with a stub body that references every parameter and injection; answers status, edits[] and summary.

Category: Editor · Compare: New Program / Main / Test

When to use it

'Add a program Main that prints X' is one call with file, name and statements:['stdout <- Stdout()', 'stdout.println(...)'] - the body included, nothing left to fill; isTest:true makes it a @Test program.

When not to use it

Details

parameters[].type must be one of the 18 whitelisted CLI arg types (String/Integer/Float/Boolean/Character/Bits/Date/Time/DateTime/Duration/Millisecond/Money/Colour/Resolution/Dimension/RegEx/GUID/List of String) — an invalid type (E07600), a typed primitive mixed with 'List of String' (E07610), or a program name already taken in the module all surface as would-fail from the dry-run gate. Programs may return only Integer (process exit code — E07590).

Arguments

ArgumentTypeRequiredWhat it is
applicationstringApplication to bind for DI — renders 'with application of <App>'. The application must resolve (define it with ek9_add_application first).
filestringyesWorkspace-relative path to the .ek9 module file the program is appended to (the 'defines program' block is created if absent). For isTest:true this must be a dev source (dev/ subdirectory or QA####_dev_ file).
injectionsarray of anyComponents pulled from the application by injection, each ONE item as DATA - {name:'code', type:'Integer'} - never a {name} and a {type} as two items, and never with '->' or '<-' in it; the tool writes the arrows and the layout. ('code as Integer' is also accepted.) A malformed item is rejected before anything is rendered. ('logger as Logger' or 'logger as Logger!' both render 'logger as Logger!'). Each is referenced in the stub (an unused injection is E11018).
isTestbooleanWhen true, prepend the @Test directive and emit an assert-based stub. Only legal in a dev source (E81015).
namestringyesProgram name (PascalCase), e.g. 'ShowInjection' or 'GreetingTest'.
parametersarray of anyTyped CLI argument parameters, each ONE item as DATA - {name:'code', type:'Integer'} - never a {name} and a {type} as two items, and never with '->' or '<-' in it; the tool writes the arrows and the layout. ('code as Integer' is also accepted.) A malformed item is rejected before anything is rendered. Each is referenced in the stub so it compiles (an unused arg is E08091).
requirementIdstringRequirement id this test anchors, e.g. 'REQ:velocity-limit' - renders '@Test: "REQ:velocity-limit"'. Requires isTest:true; supplying it for a non-test program is rejected rather than ignored. The requirement need not exist yet (writing the test first is legitimate); ek9_check_requirements reports an id that names nothing as a dangling anchor.
statementsarray of stringThe program's body, one statement or one block per entry ('stdout <- Stdout()', 'stdout.println(...)'): the program is complete in this call - no stub, no ek9_insert_statements after it. Parsed alone first; a problem names the entry and its fix.

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 12 recorded are shown.

Test program non dev rejected

Request

{
  "dryRun" : true,
  "file" : "main.ek9",
  "isTest" : true,
  "name" : "BadTest"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ ],
  "error" : {
    "message" : "@Test programs are only allowed in a dev source — move the target into a 'dev/' subdirectory or rename it to the QA####_dev_ pattern (E81015). Got: main.ek9"
  },
  "meta" : {
    "serverMs" : "<timing>"
  },
  "status" : "error",
  "summary" : "@Test programs are only allowed in a dev source — move the target into a 'dev/' subdirectory or rename it to the QA####_dev_ pattern (E81015). Got: main.ek9",
  "wouldBeDiagnostics" : [ ],
  "written" : false
}

Requirement without istest rejected

Request

{
  "dryRun" : true,
  "file" : "main.ek9",
  "name" : "NotATest",
  "requirementRef" : "REQ:velocity-limit"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ ],
  "error" : {
    "message" : "'requirementId' anchors a @Test to a requirement, so it needs isTest: true. A plain program is an entry point and cannot anchor anything. Got: REQ:velocity-limit"
  },
  "meta" : {
    "serverMs" : "<timing>"
  },
  "status" : "error",
  "summary" : "'requirementId' anchors a @Test to a requirement, so it needs isTest: true. A plain program is an entry point and cannot anchor anything. Got: REQ:velocity-limit",
  "wouldBeDiagnostics" : [ ],
  "written" : false
}

Requirement malformed rejected

Request

{
  "dryRun" : true,
  "file" : "dev/tests.ek9",
  "isTest" : true,
  "name" : "TypoTest",
  "requirementRef" : "RREQ:velocity-limit"
}

Response

{
  "conflicts" : [ ],
  "edits" : [ ],
  "error" : {
    "message" : "'RREQ:velocity-limit' is not a valid requirement id. Expected <PREFIX>:<slug> with PREFIX one of REQ, CTRL, CAP, CON and slug matching [a-z0-9-]+, e.g. 'REQ:velocity-limit'."
  },
  "meta" : {
    "serverMs" : "<timing>"
  },
  "status" : "error",
  "summary" : "'RREQ:velocity-limit' is not a valid requirement id. Expected <PREFIX>:<slug> with PREFIX one of REQ, CTRL, CAP, CON and slug matching [a-z0-9-]+, e.g. 'REQ:velocity-limit'.",
  "wouldBeDiagnostics" : [ ],
  "written" : false
}

See also