Generator: pilot analysis and fixes; G0002-G0021 tasks; handover notes merged
- Static bundle checks (name length, seed type, reserved words, contract test classes, testclasses_file), local abaplint parser check before SAP, max_tokens, robust JSON parse - Runner: G2 for CDS views with parameters, contract_check detail in report - G0020 and G0013 fixed by review and revalidated (oracle 100, null 0) - Pilot results in docs/faz1-tasarim.md 11e; handover notes merged into CLAUDE.md and docs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,22 @@ DELETE_ORDER = ["CLAS", "INTF", "PROG", "FUNC", "FUGR", "SRVD", "DDLX", "DCLS",
|
||||
SOURCE_TYPES = ("CLAS", "INTF", "PROG", "FUNC", "DDLS", "DCLS", "DDLX", "TABL")
|
||||
|
||||
|
||||
def _cds_elements(src):
|
||||
"""Element names of a CDS view select list (alias, else last path component). Used when a
|
||||
SELECT on the view is not possible, for example a view with parameters."""
|
||||
body = re.sub(r"//[^\n]*|/\*.*?\*/", "", src or "", flags=re.S)
|
||||
m = re.search(r"\{(.*)\}", body, re.S)
|
||||
out = set()
|
||||
for el in re.split(r",(?![^()]*\))", m.group(1) if m else ""):
|
||||
el = re.sub(r"@\S+(\s*:\s*('[^']*'|\S+))?", "", el).strip()
|
||||
if not el or el.lower().startswith("_") and " as " not in el.lower():
|
||||
continue
|
||||
alias = re.search(r"\bas\s+(\w+)\s*$", el, re.I)
|
||||
name = alias.group(1) if alias else re.split(r"[.\s]", el.split()[-1])[-1]
|
||||
out.add(name.upper())
|
||||
return out
|
||||
|
||||
|
||||
def _obj_args(otype, name, fg=None):
|
||||
a = {"objectType": otype, "objectName": name}
|
||||
if fg:
|
||||
@@ -222,26 +238,36 @@ class Runner:
|
||||
g1.append({"name": c["name"], "ok": ok})
|
||||
g["G1_active"] = all(x["ok"] for x in g1) and bool(g1)
|
||||
g2 = True
|
||||
g2_detail = []
|
||||
for c in contract:
|
||||
src = sources.get((c["type"], c["name"].upper()), "")
|
||||
if c.get("implements") and not re.search(rf"INTERFACES\s+{re.escape(c['implements'])}\b", src, re.I):
|
||||
g2 = False
|
||||
g2_detail.append(f"{c['name']}: does not implement {c['implements']}")
|
||||
if c["type"] == "FUNC": # signature: every parameter with its type in the FUNCTION header
|
||||
header = src.split(".", 1)[0]
|
||||
for prm in c.get("params", []):
|
||||
if not re.search(rf"\b{re.escape(prm['name'])}\b\)?\s+TYPE\s+{re.escape(prm['type'])}\b",
|
||||
header, re.I):
|
||||
g2 = False
|
||||
g2_detail.append(f"{c['name']}: no parameter {prm['name']} TYPE {prm['type']} "
|
||||
"in the FUNCTION header")
|
||||
if c["type"] == "PROG": # selection screen parameters
|
||||
for prm in c.get("parameters", []):
|
||||
if not re.search(rf"(PARAMETERS|SELECT-OPTIONS)\s*:?[^.]*\b{re.escape(prm)}\b", src, re.I):
|
||||
g2 = False
|
||||
g2_detail.append(f"{c['name']}: no selection screen parameter {prm}")
|
||||
if c["type"] == "DDLS" and c.get("fields") and g["G1_active"]:
|
||||
_, q = mcp.call("sap_sql_query", {"query": f"SELECT * FROM {c['name']}", "maxRows": 1})
|
||||
cols = {col.get("name", "").upper() for col in (_json(q) or {}).get("columns", [])}
|
||||
if not {f.upper() for f in c["fields"]} <= cols:
|
||||
if not cols: # view with parameters: SELECT without parameters fails
|
||||
cols = _cds_elements(src)
|
||||
missing = {f.upper() for f in c["fields"]} - cols
|
||||
if missing:
|
||||
g2 = False
|
||||
g2_detail.append(f"{c['name']}: CDS elements missing: {sorted(missing)}")
|
||||
g["G2_contract"] = g2 and g["G1_active"]
|
||||
rep["contract_check"] = {"g1": g1, "g2": g2_detail}
|
||||
g["G4_out_of_scope"] = all(
|
||||
_norm(self._source(mcp, o["type"], o["name"], o.get("functionGroup")))
|
||||
== _norm(seed_src[o["name"].upper()])
|
||||
|
||||
Reference in New Issue
Block a user