mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
fix: resolve type errors in javascript validator
- Add None guards for node.text before calling .decode() throughout _extract_defined_identifiers and _extract_referenced_identifiers - Add set[str] type annotations for defined/referenced sets in _check_undefined_references - Fix test assertions using "in" on str | None by adding explicit None checks Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c8284c4dcd
commit
ff3423f13f
2 changed files with 25 additions and 21 deletions
|
|
@ -75,7 +75,8 @@ def _extract_defined_identifiers(node: Node, defined: set[str]) -> None:
|
|||
if node.type in ("variable_declarator", "lexical_declaration"):
|
||||
for child in node.children:
|
||||
if child.type == "identifier":
|
||||
defined.add(child.text.decode("utf8"))
|
||||
if child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
elif child.type == "variable_declarator":
|
||||
_extract_defined_identifiers(child, defined)
|
||||
elif child.type == "object_pattern":
|
||||
|
|
@ -86,10 +87,11 @@ def _extract_defined_identifiers(node: Node, defined: set[str]) -> None:
|
|||
elif node.type == "object_pattern":
|
||||
for child in node.children:
|
||||
if child.type == "shorthand_property_identifier_pattern":
|
||||
defined.add(child.text.decode("utf8"))
|
||||
if child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
elif child.type == "pair_pattern":
|
||||
for subchild in child.children:
|
||||
if subchild.type == "identifier":
|
||||
if subchild.type == "identifier" and subchild.text is not None:
|
||||
defined.add(subchild.text.decode("utf8"))
|
||||
else:
|
||||
_extract_defined_identifiers(child, defined)
|
||||
|
|
@ -98,7 +100,8 @@ def _extract_defined_identifiers(node: Node, defined: set[str]) -> None:
|
|||
elif node.type == "array_pattern":
|
||||
for child in node.children:
|
||||
if child.type == "identifier":
|
||||
defined.add(child.text.decode("utf8"))
|
||||
if child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
else:
|
||||
_extract_defined_identifiers(child, defined)
|
||||
|
||||
|
|
@ -107,34 +110,37 @@ def _extract_defined_identifiers(node: Node, defined: set[str]) -> None:
|
|||
for child in node.children:
|
||||
if child.type == "identifier" and node.type == "function_declaration":
|
||||
# Function name
|
||||
defined.add(child.text.decode("utf8"))
|
||||
if child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
elif child.type == "formal_parameters":
|
||||
# Function parameters - extract all identifiers within
|
||||
for param_child in child.children:
|
||||
if param_child.type == "identifier":
|
||||
defined.add(param_child.text.decode("utf8"))
|
||||
if param_child.text is not None:
|
||||
defined.add(param_child.text.decode("utf8"))
|
||||
elif param_child.type in ("required_parameter", "optional_parameter"):
|
||||
for subchild in param_child.children:
|
||||
if subchild.type == "identifier":
|
||||
if subchild.type == "identifier" and subchild.text is not None:
|
||||
defined.add(subchild.text.decode("utf8"))
|
||||
elif subchild.type == "rest_pattern":
|
||||
# Rest parameters: ...args
|
||||
for rest_child in subchild.children:
|
||||
if rest_child.type == "identifier":
|
||||
if rest_child.type == "identifier" and rest_child.text is not None:
|
||||
defined.add(rest_child.text.decode("utf8"))
|
||||
|
||||
# Import statements
|
||||
elif node.type in ("import_statement", "import_specifier", "namespace_import", "import_clause"):
|
||||
for child in node.children:
|
||||
if child.type == "identifier":
|
||||
defined.add(child.text.decode("utf8"))
|
||||
if child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
else:
|
||||
_extract_defined_identifiers(child, defined)
|
||||
|
||||
# Class declarations
|
||||
elif node.type == "class_declaration":
|
||||
for child in node.children:
|
||||
if child.type == "type_identifier" or child.type == "identifier":
|
||||
if (child.type == "type_identifier" or child.type == "identifier") and child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
|
||||
# For-in and for-of loop iteration variables
|
||||
|
|
@ -147,7 +153,8 @@ def _extract_defined_identifiers(node: Node, defined: set[str]) -> None:
|
|||
found_keyword = True
|
||||
elif found_keyword and child.type == "identifier":
|
||||
# This is the iteration variable
|
||||
defined.add(child.text.decode("utf8"))
|
||||
if child.text is not None:
|
||||
defined.add(child.text.decode("utf8"))
|
||||
found_keyword = False # Only get the first identifier after the keyword
|
||||
elif child.type in ("of", "in"):
|
||||
# Stop looking after we hit of/in
|
||||
|
|
@ -184,11 +191,11 @@ def _extract_referenced_identifiers(node: Node, referenced: set[str], defined_in
|
|||
# Skip property access (e.g., obj.property - we only care about 'obj', not 'property')
|
||||
if parent.type == "member_expression":
|
||||
# Only count the object, not the property
|
||||
if parent.children and parent.children[0] == node:
|
||||
if parent.children and parent.children[0] == node and node.text is not None:
|
||||
ident = node.text.decode("utf8")
|
||||
if ident not in defined_in_scope:
|
||||
referenced.add(ident)
|
||||
else:
|
||||
elif node.text is not None:
|
||||
ident = node.text.decode("utf8")
|
||||
if ident not in defined_in_scope:
|
||||
referenced.add(ident)
|
||||
|
|
@ -203,13 +210,13 @@ def _check_undefined_references(code: str, lang: str) -> tuple[bool, str | None]
|
|||
parser = js_parser if lang == "js" else ts_parser
|
||||
tree = parser.parse(code.encode("utf8"))
|
||||
|
||||
defined = set()
|
||||
defined: set[str] = set()
|
||||
_extract_defined_identifiers(tree.root_node, defined)
|
||||
|
||||
# Add built-in globals
|
||||
defined.update(JAVASCRIPT_GLOBALS)
|
||||
|
||||
referenced = set()
|
||||
referenced: set[str] = set()
|
||||
_extract_referenced_identifiers(tree.root_node, referenced, defined)
|
||||
|
||||
# Find undefined references
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from aiservice.validators.javascript_validator import (
|
||||
validate_javascript_syntax,
|
||||
validate_typescript_syntax,
|
||||
)
|
||||
from aiservice.validators.javascript_validator import validate_javascript_syntax, validate_typescript_syntax
|
||||
|
||||
|
||||
class TestJavaScriptValidator:
|
||||
|
|
@ -231,7 +228,7 @@ type TarEntryInfo = { path: string; type: string; size: number };
|
|||
# BUG: Validating source_code alone fails
|
||||
is_valid_source_only, error_source_only = validate_typescript_syntax(source_code)
|
||||
assert not is_valid_source_only, "This demonstrates the bug - validation fails without context"
|
||||
assert "BLOCKED_TAR_ENTRY_TYPES" in error_source_only
|
||||
assert error_source_only is not None and "BLOCKED_TAR_ENTRY_TYPES" in error_source_only
|
||||
|
||||
# FIX: Validating source_code + dependency_code together should pass
|
||||
combined_code = dependency_code + "\n\n" + source_code
|
||||
|
|
@ -343,7 +340,7 @@ type TarEntryInfo = { type: string; path: string };
|
|||
# Validating source alone should fail
|
||||
is_valid_alone, error_alone = validate_typescript_syntax(source_code)
|
||||
assert not is_valid_alone, "Source alone should fail validation (missing constant)"
|
||||
assert "BLOCKED_TAR_ENTRY_TYPES" in error_alone
|
||||
assert error_alone is not None and "BLOCKED_TAR_ENTRY_TYPES" in error_alone
|
||||
|
||||
# Validating combined should pass
|
||||
combined = dependency_code + "\n\n" + source_code
|
||||
|
|
|
|||
Loading…
Reference in a new issue