REFACTOR END
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import re
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
# Configure logging
|
||||
@@ -20,7 +21,7 @@ SEMANTIC_TAXONOMY = {
|
||||
"entity", "activity", "application", "nav_host", "controller", "navigation_drawer",
|
||||
"scaffold", "dashboard", "item", "label", "location", "setup", "theme", "dependencies",
|
||||
"custom_field", "statistics", "image", "attachment", "item_creation", "item_detailed",
|
||||
"item_summary", "item_update", "summary", "update"
|
||||
"item_summary", "item_update", "summary", "update", "feature_module"
|
||||
],
|
||||
"Concern": [
|
||||
"networking", "database", "caching", "authentication", "validation", "parsing",
|
||||
@@ -74,9 +75,11 @@ class SemanticValidator:
|
||||
self.check_file_header()
|
||||
self.check_semantic_taxonomy()
|
||||
self.check_anchors()
|
||||
self.check_function_anchors()
|
||||
self.check_file_termination()
|
||||
self.check_no_stray_comments()
|
||||
self.check_contracts_and_implementation()
|
||||
self.check_relation_triplets()
|
||||
self.check_ai_friendly_logging()
|
||||
if not self.errors:
|
||||
logging.info("[INFO][SemanticValidator.validate][SUCCESS] Validation passed.")
|
||||
@@ -102,8 +105,8 @@ class SemanticValidator:
|
||||
# [POST] Errors are added to self.errors if the header is incorrect.
|
||||
# [END_CONTRACT:SemanticValidator.check_file_header]
|
||||
def check_file_header(self):
|
||||
if not self.lines[0].startswith(f"// [FILE] {self.filename}"):
|
||||
self.add_error(1, f"FileHeaderIntegrity: File must start with '// [FILE] {self.filename}'.")
|
||||
if not self.lines[0].startswith(f"// [FILE] {self.file_path.as_posix()}"):
|
||||
self.add_error(1, f"FileHeaderIntegrity: File must start with '// [FILE] {self.file_path.as_posix()}'.")
|
||||
if not self.lines[1].startswith("// [SEMANTICS]"):
|
||||
self.add_error(2, "FileHeaderIntegrity: Second line must start with '// [SEMANTICS]'.")
|
||||
# [END_ANCHOR:SemanticValidator.check_file_header]
|
||||
@@ -163,14 +166,38 @@ class SemanticValidator:
|
||||
self.add_error(line_num, f"Anchor Error: Opening anchor '// [ANCHOR:{anchor_id}:...]' at line {line_num} has no matching closing anchor.")
|
||||
# [END_ANCHOR:SemanticValidator.check_anchors]
|
||||
|
||||
# [ANCHOR:SemanticValidator.check_function_anchors:Method]
|
||||
# [CONTRACT:SemanticValidator.check_function_anchors]
|
||||
# [PURPOSE] Validates that all functions have a corresponding ANCHOR.
|
||||
# [POST] Errors are added if a function is found without an ANCHOR.
|
||||
# [END_CONTRACT:SemanticValidator.check_function_anchors]
|
||||
def check_function_anchors(self):
|
||||
fun_pattern = re.compile(r"fun\s+(.+?)\s*\(")
|
||||
anchor_pattern = re.compile(r"// \[ANCHOR:(\w+):Function\]")
|
||||
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
fun_match = fun_pattern.search(line)
|
||||
if fun_match:
|
||||
function_name = fun_match.group(1).strip()
|
||||
# Look for an ANCHOR comment in the preceding lines
|
||||
found_anchor = False
|
||||
for j in range(max(0, i-5), i): # Check up to 5 lines before the function
|
||||
anchor_match = anchor_pattern.search(self.lines[j])
|
||||
if anchor_match and anchor_match.group(1) == function_name:
|
||||
found_anchor = True
|
||||
break
|
||||
if not found_anchor:
|
||||
self.add_error(i, f"Function Anchor Error: Function '{function_name}' is missing a corresponding '// [ANCHOR:{function_name}:Function]' comment.")
|
||||
# [END_ANCHOR:SemanticValidator.check_function_anchors]
|
||||
|
||||
# [ANCHOR:SemanticValidator.check_file_termination:Method]
|
||||
# [CONTRACT:SemanticValidator.check_file_termination]
|
||||
# [PURPOSE] Validates Rule 5: FileTermination.
|
||||
# [POST] An error is added if the file does not have the correct termination anchor.
|
||||
# [END_CONTRACT:SemanticValidator.check_file_termination]
|
||||
def check_file_termination(self):
|
||||
if not self.lines[-1].strip() == f"// [END_FILE_{self.filename}]":
|
||||
self.add_error(len(self.lines), f"FileTermination: File must end with '// [END_FILE_{self.filename}]'.")
|
||||
if not self.lines[-1].strip() == f"// [END_FILE_{self.file_path.as_posix()}]":
|
||||
self.add_error(len(self.lines), f"FileTermination: File must end with '// [END_FILE_{self.file_path.as_posix()}]'.")
|
||||
# [END_ANCHOR:SemanticValidator.check_file_termination]
|
||||
|
||||
# [ANCHOR:SemanticValidator.check_no_stray_comments:Method]
|
||||
@@ -201,13 +228,30 @@ class SemanticValidator:
|
||||
end_contract_pattern = re.compile(r"// \[END_CONTRACT:(\w+)\]")
|
||||
pre_pattern = re.compile(r'// \[PRE\](.*)')
|
||||
post_pattern = re.compile(r'// \[POST\](.*)')
|
||||
fun_pattern = re.compile(r"fun\s+\w+\(.*\)\s*\{")
|
||||
fun_pattern = re.compile(r"fun\s+(.+?)\(.*\)\s*\{")
|
||||
|
||||
in_contract = False
|
||||
contract_id = None
|
||||
pre_conditions = []
|
||||
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
fun_match = fun_pattern.search(line)
|
||||
if fun_match:
|
||||
function_name = fun_match.group(1).strip()
|
||||
# Check for CONTRACT comment in the preceding lines
|
||||
found_contract = False
|
||||
for j in range(max(0, i-5), i): # Check up to 5 lines before the function
|
||||
contract_match = contract_pattern.search(self.lines[j])
|
||||
if contract_match:
|
||||
contract_id_from_comment = contract_match.group(1)
|
||||
if contract_id_from_comment == function_name: # Check if contract ID matches function name
|
||||
found_contract = True
|
||||
break
|
||||
else:
|
||||
self.add_error(j, f"Function Contract Error: Contract ID '{contract_id_from_comment}' does not match function name '{function_name}'.")
|
||||
if not found_contract:
|
||||
self.add_error(i, f"Function Contract Error: Function '{function_name}' is missing a corresponding '// [CONTRACT:{function_name}]' comment.")
|
||||
|
||||
if contract_pattern.search(line):
|
||||
in_contract = True
|
||||
contract_id = contract_pattern.search(line).group(1)
|
||||
@@ -255,6 +299,49 @@ class SemanticValidator:
|
||||
return len(self.lines) -1 # fallback
|
||||
# [END_ANCHOR:SemanticValidator.check_contracts_and_implementation]
|
||||
|
||||
# [ANCHOR:SemanticValidator.check_function_contracts:Method]
|
||||
# [CONTRACT:SemanticValidator.check_function_contracts]
|
||||
# [PURPOSE] Validates that all functions have a corresponding CONTRACT.
|
||||
# [POST] Errors are added if a function is found without a CONTRACT.
|
||||
# [END_CONTRACT:SemanticValidator.check_function_contracts]
|
||||
def check_function_contracts(self):
|
||||
fun_pattern = re.compile(r"fun\s+(.+?)\(.*\)\s*\{")
|
||||
contract_pattern = re.compile(r"// \[CONTRACT:(\w+)\]")
|
||||
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
fun_match = fun_pattern.search(line)
|
||||
if fun_match:
|
||||
function_name = fun_match.group(1).strip()
|
||||
# Look for a CONTRACT comment in the preceding lines
|
||||
found_contract = False
|
||||
for j in range(max(0, i-5), i): # Check up to 5 lines before the function
|
||||
contract_match = contract_pattern.search(self.lines[j])
|
||||
if contract_match and contract_match.group(1) == function_name:
|
||||
found_contract = True
|
||||
break
|
||||
if not found_contract:
|
||||
self.add_error(i, f"Function Contract Error: Function '{function_name}' is missing a corresponding '// [CONTRACT:{function_name}]' comment.")
|
||||
# [END_ANCHOR:SemanticValidator.check_function_contracts]
|
||||
|
||||
# [ANCHOR:SemanticValidator.check_relation_triplets:Method]
|
||||
# [CONTRACT:SemanticValidator.check_relation_triplets]
|
||||
# [PURPOSE] Validates the syntax of relation triplets within ANCHOR blocks.
|
||||
# [POST] Errors are added for invalid relation triplet syntax or unknown predicates.
|
||||
# [END_CONTRACT:SemanticValidator.check_relation_triplets]
|
||||
def check_relation_triplets(self):
|
||||
relation_pattern = re.compile(r"// \[RELATION:(\w+):(\w+)\]")
|
||||
valid_predicates = ["CALLS", "CREATES_INSTANCE_OF", "INHERITS_FROM", "IMPLEMENTS",
|
||||
"READS_FROM", "WRITES_TO", "MODIFIES_STATE_OF", "DEPENDS_ON",
|
||||
"DISPATCHES_EVENT", "OBSERVES", "TRIGGERS", "EMITS_STATE", "CONSUMES_STATE"]
|
||||
|
||||
for i, line in enumerate(self.lines, 1):
|
||||
match = relation_pattern.search(line)
|
||||
if match:
|
||||
predicate, object_id = match.groups()
|
||||
if predicate not in valid_predicates:
|
||||
self.add_error(i, f"Relation Triplet Error: Invalid predicate '{predicate}' in relation triplet.")
|
||||
# [END_ANCHOR:SemanticValidator.check_relation_triplets]
|
||||
|
||||
# [ANCHOR:SemanticValidator.check_ai_friendly_logging:Method]
|
||||
# [CONTRACT:SemanticValidator.check_ai_friendly_logging]
|
||||
# [PURPOSE] Validates Principle A: AIFriendlyLogging.
|
||||
@@ -288,22 +375,44 @@ class SemanticValidator:
|
||||
# [POST] Exits with code 0 on validation success.
|
||||
# [END_CONTRACT:main_execution]
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("[ERROR][main_execution][FATAL] Incorrect number of arguments provided.")
|
||||
print("Usage: python validate_semantics.py <file_path>")
|
||||
parser = argparse.ArgumentParser(description="Validate Kotlin source files against the Semantic Enrichment Protocol.")
|
||||
parser.add_argument("paths", nargs="+", help="One or more file paths or directory paths to validate.")
|
||||
args = parser.parse_args()
|
||||
|
||||
all_files_to_validate = []
|
||||
for path_str in args.paths:
|
||||
path = Path(path_str)
|
||||
if path.is_file() and path.suffix == ".kt":
|
||||
all_files_to_validate.append(path)
|
||||
elif path.is_dir():
|
||||
for kt_file in path.rglob("*.kt"):
|
||||
all_files_to_validate.append(kt_file)
|
||||
else:
|
||||
logging.warning("[WARNING][main_execution][SKIP] Skipping invalid path: %s (not a .kt file or directory).", path_str)
|
||||
|
||||
if not all_files_to_validate:
|
||||
logging.error("[ERROR][main_execution][FATAL] No .kt files found to validate.")
|
||||
sys.exit(1)
|
||||
|
||||
file_to_validate = sys.argv[1]
|
||||
validator = SemanticValidator(file_to_validate)
|
||||
errors = validator.validate()
|
||||
overall_success = True
|
||||
for file_path in all_files_to_validate:
|
||||
logging.info("\n[INFO][main_execution][START] Validating file: %s", file_path)
|
||||
validator = SemanticValidator(file_path)
|
||||
errors = validator.validate()
|
||||
|
||||
if errors:
|
||||
print(f"Semantic validation failed for {file_to_validate}:")
|
||||
for error in errors:
|
||||
print(f"- {error}")
|
||||
if errors:
|
||||
overall_success = False
|
||||
print(f"Semantic validation failed for {file_path}:")
|
||||
for error in errors:
|
||||
print(f"- {error}")
|
||||
else:
|
||||
print(f"Semantic validation passed for {file_path}.")
|
||||
|
||||
if not overall_success:
|
||||
print("\n[ERROR][main_execution][SUMMARY] One or more files failed semantic validation.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"Semantic validation passed for {file_to_validate}.")
|
||||
print("\n[INFO][main_execution][SUMMARY] All specified .kt files passed semantic validation.")
|
||||
# [END_ANCHOR:main_execution]
|
||||
|
||||
# [END_FILE_validate_semantics.py]
|
||||
Reference in New Issue
Block a user