285 lines
8.8 KiB
Plaintext
285 lines
8.8 KiB
Plaintext
' ===================================================================
|
|
' File: command-parser.puml
|
|
' Purpose: Single source of truth for module-level activity + per-method sequences.
|
|
' Module: command-parser.js — Extract/parse YAML-like @bridge@ blocks; defaults; validation.
|
|
' Edit rules: Follow the legend at bottom; preserve VIEW/METHOD anchors for automation.
|
|
' ===================================================================
|
|
|
|
' (Optional) neutral defaults — typography/layout only (keeps partition colors intact)
|
|
skinparam Shadowing false
|
|
skinparam SequenceMessageAlign center
|
|
skinparam SequenceLifeLineBorderColor #666666
|
|
skinparam SequenceLifeLineBorderThickness 1
|
|
|
|
' ==== VIEW: Branch Flow (command-parser.js) =================================
|
|
@startuml
|
|
title command-parser.js — Branch Flow (full module)
|
|
|
|
start
|
|
:command-parser;
|
|
|
|
fork
|
|
' -------- REQUIRED (static map) --------
|
|
partition "REQUIRED (action → required fields[])" #E7FAE3 {
|
|
:REQUIRED;
|
|
:get_file:[action,repo,path]\n\n update_file:[action,repo,path,content]\n\n create_file:[action,repo,path,content]\n\n create_repo:[action,repo]\n\n create_branch:[action,repo,branch]\n\n create_pr:[action,repo,title,head,base]\n\n list_files:[action,repo,path];
|
|
kill
|
|
}
|
|
fork again
|
|
' -------- parse(text) --------
|
|
partition "parse(text)" #FFF6D1 {
|
|
:parse;
|
|
:block = extractBlock(text) or throw;
|
|
:obj = parseKV(block);
|
|
:applyDefaults(obj);
|
|
:return obj;
|
|
kill
|
|
}
|
|
fork again
|
|
' -------- extractBlock(text) --------
|
|
partition "extractBlock(text)" #FFE1DB {
|
|
:extractBlock;
|
|
:regex /^\s*@bridge@\\n([\\s\\S]*?)\\n@end@/m;\nreturn inner or null;
|
|
kill
|
|
}
|
|
fork again
|
|
' -------- parseKV(block) --------
|
|
partition "parseKV(block)" #DCF9EE {
|
|
:parseKV;
|
|
:scan lines; support "key: value" and "key: |" multiline;
|
|
:flush() helper to commit multiline;
|
|
:return object;
|
|
kill
|
|
}
|
|
fork again
|
|
' -------- applyDefaults(obj) --------
|
|
partition "applyDefaults(obj)" #FFE6F0 {
|
|
:applyDefaults;
|
|
:url default; owner default;\ncreate_branch -> source_branch default;\nrepo "owner/repo" split;
|
|
:return void;
|
|
kill
|
|
}
|
|
fork again
|
|
' -------- validate(obj) --------
|
|
partition "validate(obj)" #E6F3FF {
|
|
:validate;
|
|
:honor example flag -> {isValid:true, example:true};
|
|
:check action presence + known action;
|
|
:ensure REQUIRED fields present;
|
|
:return {isValid, errors[], example?};
|
|
kill
|
|
}
|
|
end fork
|
|
@enduml
|
|
|
|
' ==== METHOD: parse(text) ===================================================
|
|
@startuml
|
|
title command-parser:parse(text): \n Extract first block, parse KV, apply defaults, return object
|
|
|
|
participant "Caller" as CL
|
|
participant "parse(text)" as PAR
|
|
participant "extractBlock(text)" as EXT
|
|
participant "parseKV(block)" as PKV
|
|
participant "applyDefaults(obj)" as DEF
|
|
|
|
activate CL
|
|
CL -> PAR : initial request (text)
|
|
activate PAR
|
|
|
|
PAR -> EXT : extractBlock(text)
|
|
EXT --> PAR : block | null
|
|
alt block == null
|
|
PAR -> PAR : throw Error("No complete @bridge@ command found (missing @end@)")
|
|
PAR --> CL : (exception) ' (diagram note: thrown)
|
|
else block found
|
|
PAR -> PKV : parseKV(block)
|
|
PKV --> PAR : obj
|
|
PAR -> DEF : applyDefaults(obj)
|
|
DEF --> PAR : (void)
|
|
PAR --> CL : obj
|
|
end
|
|
|
|
deactivate PAR
|
|
deactivate CL
|
|
@enduml
|
|
|
|
' ==== METHOD: extractBlock(text) ===========================================
|
|
@startuml
|
|
title command-parser:extractBlock(text): \n Return inner text between @bridge@ and @end@ or null
|
|
|
|
participant "Caller" as CL
|
|
participant "extractBlock(text)" as EXT
|
|
|
|
activate CL
|
|
CL -> EXT : text
|
|
activate EXT
|
|
EXT -> EXT : m = /\\s*@bridge@\\s*\\n([\\s\\S]*?)\\n@end@/m.exec(text)
|
|
EXT -> EXT : return m?.[1]?.trim() || null
|
|
EXT --> CL : block | null
|
|
deactivate EXT
|
|
deactivate CL
|
|
@enduml
|
|
|
|
' ==== METHOD: parseKV(block) ===============================================
|
|
@startuml
|
|
title command-parser:parseKV(block): \n Minimal YAML-like parser with multiline "|" support
|
|
|
|
participant "Caller" as CL
|
|
participant "parseKV(block)" as PKV
|
|
participant "flush()" as FL
|
|
|
|
activate CL
|
|
CL -> PKV : block
|
|
activate PKV
|
|
|
|
PKV -> PKV : out = {}; lines = block.split('\\n')\ncurKey=null; multi=false; buf=[]
|
|
PKV -> FL : define flush(): if (multi && curKey) out[curKey]=buf.join('\\n').replace(/\\s+$/,''); reset
|
|
FL --> PKV : (ready)
|
|
|
|
loop for each line
|
|
PKV -> PKV : normalize CR; line = raw.replace(/\\r$/,'')
|
|
alt multi is true
|
|
alt new unindented key pattern
|
|
PKV -> FL : flush()
|
|
FL --> PKV : ok
|
|
else still multiline
|
|
PKV -> PKV : buf.push(line)
|
|
' continue
|
|
end
|
|
end
|
|
|
|
PKV -> PKV : idx = line.indexOf(':')
|
|
alt idx != -1
|
|
PKV -> PKV : key = line[0:idx].trim(); value = line[idx+1:].trim()
|
|
alt value == "|"
|
|
PKV -> PKV : curKey=key; multi=true; buf=[]
|
|
else single-line
|
|
PKV -> PKV : out[key] = value; curKey=key
|
|
end
|
|
else if (multi)
|
|
PKV -> PKV : buf.push(line)
|
|
end
|
|
end
|
|
|
|
PKV -> FL : flush()
|
|
FL --> PKV : ok
|
|
PKV --> CL : out
|
|
deactivate PKV
|
|
deactivate CL
|
|
@enduml
|
|
|
|
' ==== METHOD: applyDefaults(obj) ===========================================
|
|
@startuml
|
|
title command-parser:applyDefaults(obj): \n Set sane defaults and split owner/repo when needed
|
|
|
|
participant "Caller" as CL
|
|
participant "applyDefaults(obj)" as DEF
|
|
|
|
activate CL
|
|
CL -> DEF : obj
|
|
activate DEF
|
|
|
|
DEF -> DEF : p.url ||= "https://n8n.brrd.tech/webhook/ai-gitea-bridge"
|
|
DEF -> DEF : p.owner ||= "rob"
|
|
DEF -> DEF : if action == "create_branch" && !source_branch -> "main"
|
|
DEF -> DEF : if typeof repo == string && repo.includes("/")\n [owner,repo] = repo.split("/",2);\n if !p.owner then p.owner=owner;\n p.repo=repo;
|
|
|
|
DEF --> CL : (void)
|
|
deactivate DEF
|
|
deactivate CL
|
|
@enduml
|
|
|
|
' ==== METHOD: validate(obj) ================================================
|
|
@startuml
|
|
title command-parser:validate(obj): \n Respect example flag, ensure action known, check required fields
|
|
|
|
participant "Caller" as CL
|
|
participant "validate(obj)" as VAL
|
|
participant "REQUIRED" as REQ
|
|
alt
|
|
else example flag
|
|
activate CL
|
|
CL -> VAL : obj
|
|
activate VAL
|
|
|
|
' example flag short-circuit
|
|
VAL -> VAL : if p.example == true/"true"/"yes" -> return {isValid:true, errors:[], example:true}
|
|
VAL --> CL : {isValid:true, errors:[], example:true}
|
|
deactivate VAL
|
|
' (The diagram returns here in example case)
|
|
else no example flag
|
|
|
|
' Normal path (no example):
|
|
CL -> VAL : obj (no example)
|
|
activate VAL
|
|
|
|
VAL -> VAL : if !p.action -> {isValid:false, errors:["Missing required field: action"]}
|
|
VAL -> REQ : req = REQUIRED[p.action]
|
|
REQ --> VAL : fields[] | undefined
|
|
alt
|
|
else unknown action
|
|
VAL --> CL : {isValid:false, errors:[`Unknown action: ${action}`]}
|
|
else known action
|
|
VAL -> VAL : for f in req: if missing -> errors.push(...)
|
|
VAL --> CL : {isValid: errors.length==0, errors}
|
|
end
|
|
|
|
deactivate VAL
|
|
deactivate CL
|
|
end
|
|
@enduml
|
|
|
|
' ==== LEGEND ================================================================
|
|
@startuml
|
|
legend bottom
|
|
== command-parser UML Style Guide (for future edits) ==
|
|
• Scope: One .puml per module. Keep two views:
|
|
(1) Activity "Branch Flow" for the whole module (partitions + soft colors),
|
|
(2) Per-function Sequence diagrams for each exported or significant internal method.
|
|
|
|
• Sequence conventions:
|
|
1) First participant is the external caller (use "Caller" or a concrete origin).
|
|
2) Do NOT add a module lifeline; the module name appears in the title only.
|
|
3) Include every directly-called method or subsystem as a participant
|
|
(e.g., "parse(text)", "extractBlock(text)", "parseKV(block)", "applyDefaults(obj)", "validate(obj)", "REQUIRED", "flush()").
|
|
4) Prefer simple messages; Use --> for returns; -> for calls.
|
|
5) Use activate/deactivate as you see fit for clarity (no strict rule).
|
|
6) Use alt blocks only when branches meaningfully change the message flow.
|
|
|
|
• Activity view conventions:
|
|
A) Start with module node then fork partitions for each function/method.
|
|
B) One partition per function; soft background color; terminate branches with 'kill'.
|
|
C) Keep wording aligned with code (e.g., “deepClone(DEFAULT_CONFIG)”, exact error wording).
|
|
|
|
• Color palette (soft pastels)
|
|
• Use --> for returns; -> for calls.
|
|
• Participants use quoted method names for internals (e.g., "parseKV(block)"), and plain nouns for structures ("REQUIRED").
|
|
• Keep this legend at the end of the file to standardize edits.
|
|
|
|
UML_Example
|
|
------------------------------------------
|
|
title moduleName:methodName(args): \n Detailed description of what this method does
|
|
|
|
participant "Caller" as CL
|
|
participant "methodName()" as M
|
|
' Add collaborators as needed:
|
|
' participant "Dependency" as DEP
|
|
' participant "AnotherMethod()" as AM
|
|
|
|
activate CL
|
|
CL -> M : initial request (args)
|
|
activate M
|
|
' -- inner flow (keep alt blocks only if they clarify) --
|
|
' M -> DEP : call something
|
|
' DEP --> M : result
|
|
' alt branch condition
|
|
' M -> AM : call another
|
|
' AM --> M : result
|
|
' end
|
|
M --> CL : return value
|
|
deactivate M
|
|
deactivate CL
|
|
------------------------------------------
|
|
endlegend
|
|
@enduml
|