module Noir::TreeSitterKotlinParameterExtractor

Overview

Tree-sitter-backed parameter extractor for Kotlin Spring.

Mirrors TreeSitterJavaParameterExtractor for the Kotlin AST (parameter modifiers come before the parameter, primary constructor properties carry DTO fields, annotation arguments use value_arguments instead of annotation_argument_list).

Covered:

Not covered yet (see #1298):

Extended Modules

Defined in:

miniparsers/kotlin_parameter_extractor_ts.cr

Constant Summary

HTTP_HEADER_SPECIAL_CASES = {"Etag" => "ETag", "Te" => "TE", "Www-Authenticate" => "WWW-Authenticate", "X-Frame-Options" => "X-Frame-Options"}
INJECTED_PARAM_ANNOTATIONS = Set {"AuthenticationPrincipal", "CurrentUser", "CurrentSecurityContext", "SessionAttribute", "RequestAttribute"}

Parameter annotations whose value is supplied by a Spring argument resolver, not bound from the HTTP request the client controls. A parameter carrying one of these is NOT an attack-surface input even when its type is a bindable DTO (the classic @AuthenticationPrincipal user: User, or a custom meta-annotation like @CurrentUser), so it must be excluded from the un-annotated implicit-binding path that would otherwise expand its DTO fields into phantom params. Validation annotations (@Valid, …) are intentionally absent — they leave binding semantics untouched.

PRIMITIVE_TYPES = Set {"long", "int", "integer", "short", "byte", "char", "character", "boolean", "string", "float", "double", "number", "bigdecimal", "biginteger", "uuid", "date", "localdate", "localdatetime", "localtime", "instant", "multipartfile"}

Scalar types Spring binds from a single request value. Type names are first resolved to their leaf identifier by leaf_type_name (so List<Long> reduces to List); annotated request params emit by name regardless of type. Mirrors the Java extractor's SIMPLE_PARAM_TYPES so @RequestParam ids: List<Long> surfaces instead of being silently dropped.

QUERY_VERB_PARAMS = Set {"GET", "HEAD", "OPTIONS"}

Verbs whose params = [...] constraint emits as query parameters. Anything else uses form data.

Instance Method Summary

Instance Method Detail

def extract_class_fields(source : String) : Hash(String, Array(FieldInfo)) #

Extract {class_name => [FieldInfo]} from source. Kotlin DTO fields can come from:

  1. Primary constructor parameters declared with val / var (the common data class Foo(val a: Int, var b: String) idiom).
  2. property_declaration nodes inside the class body (var/ val properties on regular classes).

Properties are treated as setter-accessible by default — Kotlin synthesises setters for var, and val properties usually serialise just fine for our endpoint-fan-out purposes.


[View source]
def extract_class_fields_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, Array(FieldInfo)) #

_from(root, source, ...) variants accept a pre-parsed root so the Kotlin Spring analyzer can amortise the tree-sitter parse across multiple extractions on the same file. Tree lifetime is the caller's responsibility.


[View source]
def extract_class_supertypes(source : String) : Hash(String, String) #

Map each class to the simple name of its superCLASS (the supertype invoked with (), e.g. class Owner : Person(){"Owner" => "Person"}). Interface supertypes (: Foo without parens) carry no bindable fields and are skipped. Drives the DTO index's cross-file inheritance merge so a command object that extends a base class inherits its bindable fields.


[View source]
def extract_class_supertypes_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, String) #

[View source]
def extract_consumes(source : String, class_name : String, method_name : String) : String | Nil #

Read consumes = ["..."] / consumes = arrayOf("...") off the method's mapping annotation. Returns "form" / "json" / nil.


[View source]
def extract_consumes_from(root : LibTreeSitter::TSNode, source : String, class_name : String, method_name : String) : String | Nil #

[View source]
def extract_consumes_from_method(method : LibTreeSitter::TSNode, source : String) : String | Nil #

[View source]
def extract_imports(source : String) : Array(ImportDecl) #

[View source]
def extract_imports_from(root : LibTreeSitter::TSNode, source : String) : Array(ImportDecl) #

[View source]
def extract_method_parameters(source : String, class_name : String, method_name : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo)), string_constants = Hash(String, String).new, local_string_constants = Hash(String, String).new) : Array(Param) #

Walk method formal parameters + synthesised params=/headers= constraints on the method's mapping annotation. Returns the combined parameter list in the order the legacy analyzer emitted them: formal-parameter sweep first, constraint sweep appended.


[View source]
def extract_method_parameters_from(root : LibTreeSitter::TSNode, source : String, class_name : String, method_name : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo)), string_constants = Hash(String, String).new, local_string_constants = Hash(String, String).new) : Array(Param) #

[View source]
def extract_method_parameters_from_method(method : LibTreeSitter::TSNode, source : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo)), string_constants = Hash(String, String).new, local_string_constants = Hash(String, String).new) : Array(Param) #

[View source]
def extract_package_name(source : String) : String #

[View source]
def extract_package_name_from(root : LibTreeSitter::TSNode, source : String) : String #

[View source]
def extract_server_request_parameters_from_method(method : LibTreeSitter::TSNode, source : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo))) : Array(Param) #

[View source]
def index_functions_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, LibTreeSitter::TSNode) #

[View source]