diff --git a/cldk/analysis/c/__init__.py b/cldk/analysis/c/__init__.py deleted file mode 100644 index a47394b..0000000 --- a/cldk/analysis/c/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -C package -""" diff --git a/cldk/analysis/c/treesitter/__init__.py b/cldk/analysis/c/treesitter/__init__.py deleted file mode 100644 index aa31c2c..0000000 --- a/cldk/analysis/c/treesitter/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Treesitter package -""" - -from cldk.analysis.c.treesitter.c_sitter import CSitter - -__all__ = ["CSitter"] diff --git a/cldk/analysis/c/treesitter/c_sitter.py b/cldk/analysis/c/treesitter/c_sitter.py deleted file mode 100644 index 44e926a..0000000 --- a/cldk/analysis/c/treesitter/c_sitter.py +++ /dev/null @@ -1,530 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -CSitter module -""" - -from typing import List -from tree_sitter import Language, Parser, Query, Node -import tree_sitter_c as tsc - -from cldk.models.c.models import CFunction, CImport, CParameter, CTranslationUnit, COutput -from cldk.models.treesitter import Captures - - -class CSitter: - """ - Tree sitter for C use cases. - """ - - def __init__(self) -> None: - self.language: Language = Language(tsc.language()) - self.parser: Parser = Parser(self.language) - - def get_all_functions(self, code: str) -> List[CFunction]: - """ - Get all the functions in the provided code. - - Parameters - ---------- - code: the code you want to analyse. - - Returns - ------- - List[CFunction] - returns all the function details within the provided code. - """ - - return [self.__get_function_details(code, capture.node) for capture in self.__get_function_nodes(code)] - - def get_imports(self, code: str) -> List[CImport]: - """ - Get all the imports in the provided code. - - Parameters - ---------- - code: the code you want to analyse. - - Returns - ------- - List[CImport] - returns all the imports within the provided code. - """ - - query = """(preproc_include) @import""" - captures: Captures = self.__frame_query_and_capture_output(query, code) - imports: List[CImport] = [] - for capture in captures: - path_node: Node = capture.node.child_by_field_name("path") - text: str = path_node.text.decode() - if path_node.type == "system_lib_string": - imports.append(CImport(value=text[1 : len(text) - 1], is_system=True)) - elif path_node.type == "string_literal": - imports.append(CImport(value=text[1 : len(text) - 1], is_system=False)) - else: - imports.append(CImport(value=text, is_system=False)) - - return imports - - def get_translation_unit_details(self, code: str) -> CTranslationUnit: - """ - Given the code of a C translation unit, return the details. - - Parameters - ---------- - code : str - The source code of the translation unit. - - Returns - ------- - CTranslationUnit - The details of the given translation unit. - """ - - return CTranslationUnit( - functions=self.get_all_functions(code), - imports=self.get_imports(code), - ) - - def __get_function_details(self, original_code: str, node: Node) -> CFunction: - """ - Extract the details of a function from a tree-sitter node. - - Parameters - ---------- - original_code : str - The original code, used to extract the tree-sitter node. - node : Node - The function tree-sitter node we want to evaluate. - - Returns - ------- - CFunction - The extracted details of the function. - """ - - nb_pointers = self.__count_pointers(node.child_by_field_name("declarator")) - return_type: str = self.__get_function_return_type(node) - if return_type != "function": - return_type = return_type + nb_pointers * "*" - - output: COutput = COutput( - type=return_type, - is_reference=return_type == "function" or nb_pointers > 0, - qualifiers=self.__get_type_qualifiers(node), - ) - - return CFunction( - name=self.__get_function_name(node), - code=node.text.decode(), - start_line=node.start_point[0], - end_line=node.end_point[0], - signature=self.__get_function_signature(original_code, node), - parameters=self.__get_function_parameters(node), - output=output, - comment=self.__get_comment(node), - specifiers=self.__get_storage_class_specifiers(node), - ) - - def __get_function_parameters(self, function_node: Node) -> List[CParameter]: - """ - Extract the parameters of a tree-sitter function node. - - Parameters - ---------- - function_node : Node - The function node whose parameters we want to extract. - - Returns - ------- - List[CParameter] - The parameters of the given function node. - """ - - query = """(function_declarator ((parameter_list) @function.parameters))""" - parameters_list: Captures = self.__query_node_and_capture_output(query, function_node) - - if not parameters_list: - return [] - - params: dict[str, CParameter] = self.__get_parameter_details(parameters_list) - - # for old-style function definition: - # https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Old_002dStyle-Function-Definitions.html - - for child in function_node.children: - if child.type == "declaration": - for tup in self.__extract_parameter_declarations(child): - name, parameter = tup - params[name] = parameter - - # filter out params without type - return [param[1] for param in params.items() if param[1].type] - - def __frame_query_and_capture_output(self, query: str, code_to_process: str) -> Captures: - """Frame a query for the tree-sitter parser. - - Parameters - ---------- - query : str - The query to frame. - code_to_process : str - The code to process. - - Returns - ------- - Captures - The list of tree-sitter captures. - """ - - framed_query: Query = self.language.query(query) - tree = self.parser.parse(bytes(code_to_process, "utf-8")) - return Captures(framed_query.captures(tree.root_node)) - - def __query_node_and_capture_output(self, query: str, node: Node) -> Captures: - """Frame a query for the tree-sitter parser and query the given tree-sitter node. - - Parameters - ---------- - query : str - The query to frame. - node : Node - The root node used for querying. - - Returns - ------- - Captures - The list of tree-sitter captures. - """ - - framed_query: Query = self.language.query(query) - return Captures(framed_query.captures(node)) - - def __get_function_nodes(self, code: str) -> Captures: - """Parse the given code and extract tree-sitter function nodes. - - Parameters - ---------- - code : str - The input code. - - Returns - ------- - Captures - The list of tree-sitter captures. - """ - - query = """((function_definition) @function)""" - return self.__frame_query_and_capture_output(query, code) - - def __get_function_name(self, function_node: Node) -> str: - """ - Extract the function name from a tree-sitter function node. - - Parameters - ---------- - function_node : Node - The function node whose name we want to extract. - - Returns - ------- - str - The name of the function. - """ - - query = """(function_declarator ((identifier) @function.name))""" - function_name_node: Node = self.__query_node_and_capture_output(query, function_node)[0].node - return function_name_node.text.decode() - - def __get_function_return_type(self, function_node: Node) -> str: - """ - Extracts the return type of a tree-sitter function node. - - Parameters - ---------- - function_node : Node - The function node whose return type we want to extract. - - Returns - ------- - str - The return type of a function or function, if the return is a function pointer. - """ - - # TODO: not sure if this is correct - # if there's more that 1 function declaration type, we consider it a function pointer - if self.__count_function_declarations(function_node.child_by_field_name("declarator")) > 1: - return "function" - - type_node = function_node.child_by_field_name("type") - - return type_node.text.decode() if type_node.type != "struct_specifier" else type_node.child_by_field_name("name").text.decode() - - def __get_function_signature(self, code: str, function_node: Node) -> str: - """ - Extracts the function signature from a tree-sitter function node. - - Parameters - ---------- - code : str - The original code that was used to extract the function node. - function_node : Node - The function node whose signature we want to extract. - - Returns - ------- - str - The signature of the function. - """ - - body_node: Node = function_node.child_by_field_name("body") - start_byte = function_node.start_byte - end_byte = body_node.start_byte - code_bytes = bytes(code, "utf-8") - signature = code_bytes[start_byte:end_byte] - - return signature.decode().strip() - - def __get_type_qualifiers(self, node: Node) -> List[str]: - """ - Extract the type qualifiers from a given tree-sitter node. - - Paramaters - ---------- - node : Node - The node whose type qulifiers we want to extract. - - Returns - ------- - List[str] - The list of type qualifiers. - """ - - if not node or not node.children: - return [] - - return [child.text.decode() for child in node.children if child.type == "type_qualifier"] - - def __get_storage_class_specifiers(self, node: Node) -> List[str]: - """ - Extract the storage class specifiers from a given tree-sitter node. - - Paramaters - ---------- - node : Node - The node whose storage class speciers we want to extract. - - Returns - ------- - List[str] - The list of storage class specifiers. - """ - - if not node or not node.children: - return [] - - return [child.text.decode() for child in node.children if child.type == "storage_class_specifier"] - - def __count_pointers(self, node: Node) -> int: - """ - Count the number of consecutive pointers for a tree-sitter node. - - Parameters - ---------- - node : Node - The tree-siter node we want to evaluate. - - Returns - ------- - int - The number of consecutive pointers present in the given tree-sitter node. - """ - - count = 0 - curr_node = node - while curr_node and curr_node.type == "pointer_declarator": - count += 1 - curr_node = curr_node.child_by_field_name("declarator") - - return count - - def __count_function_declarations(self, node: Node) -> int: - """ - Counts the number of function declaration nodes for a tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter node we want to evaluate. - - Returns - ------- - int - The number of function delacration nodes present in the given tree-sitter node. - """ - - if not node or not node.children: - return 0 - - sum = 1 if node.type == "function_declarator" else 0 - for child in node.children: - sum += self.__count_function_declarations(child) - - return sum - - def __get_parameter_details(self, parameters_list: Captures) -> dict[str, CParameter]: - """ - Extract parameter details from a list of tree-sitter parameters. - - Parameters - ---------- - parameters_list : Captures - The parameter list node captures. - - Returns - ------- - Dict[str, CParameter] - A dictionary of parameter details. - """ - - params: dict[str, CParameter] = {} - - for parameters in parameters_list: - if not parameters or not parameters.node.children: - continue - for param in parameters.node.children: - # old c style - if param.type == "identifier": - name, parameter = self.__extract_simple_parameter(param, "") - params[name] = parameter - elif param.type == "variadic_parameter": - name, parameter = self.__extract_simple_parameter(param, "variadic") - params[name] = parameter - elif param.type == "parameter_declaration": - for tup in self.__extract_parameter_declarations(param): - name, parameter = tup - params[name] = parameter - - return params - - def __extract_simple_parameter(self, node: Node, parameter_type: str) -> tuple[str, CParameter]: - name: str = node.text.decode() - parameter: CParameter = CParameter( - type=parameter_type, - qualifiers=[], - specifiers=[], - is_reference=False, - name=name, - ) - - return (name, parameter) - - def __extract_parameter_declarations(self, node: Node) -> List[tuple[str, CParameter]]: - query = """((identifier) @name)""" - captures: Captures = self.__query_node_and_capture_output(query, node) - - # no name found, skip this node - if len(captures) == 0: - return [] - - parameters: List[tuple[str, CParameter]] = [] - for capture in captures: - parameters.append(self.__extract_parameter_declaration(node, capture.node)) - - return parameters - - def __extract_parameter_declaration(self, parent_node: Node, identifier_node: Node) -> tuple[str, CParameter]: - name = identifier_node.text.decode() - - nb_function_declarations = self.__count_function_declarations(parent_node) - # we have a function pointer - if nb_function_declarations > 0: - parameter: CParameter = CParameter( - type="function", - qualifiers=[], # TODO: not sure if this is correct - specifiers=[], # TODO: not sure if this is correct - is_reference=True, - name=name, - ) - return (name, parameter) - - type_node = parent_node.child_by_field_name("type") - - param_type: str = type_node.text.decode() if type_node.type != "struct_specifier" else type_node.child_by_field_name("name").text.decode() - type_augmentor = self.__augment_type(identifier_node, parent_node.type) - - parameter = CParameter( - type=param_type + type_augmentor, - qualifiers=self.__get_type_qualifiers(parent_node), - specifiers=self.__get_storage_class_specifiers(parent_node), - is_reference=type_augmentor.startswith("*"), - name=name, - ) - - return (name, parameter) - - def __augment_type(self, identifier_node: Node, stop_node_type: str) -> str: - """ - Augment types with pointer and array details. - """ - - # not sure about this one - type_augmentor = "" - pointer_augmentor = "" - array_augmentor = "" - curr_node = identifier_node.parent - while curr_node and curr_node.type != stop_node_type: - if curr_node.type == "pointer_declarator": - pointer_augmentor = f"*{pointer_augmentor}" - elif curr_node.type == "array_declarator": - size_node = curr_node.child_by_field_name("size") - size: str = "" - if size_node: - size = size_node.text.decode() - array_augmentor = f"{array_augmentor}[{size}]" - elif curr_node.type == "parenthesized_declarator": - type_augmentor = f"({pointer_augmentor}{type_augmentor}{array_augmentor})" - pointer_augmentor = "" - array_augmentor = "" - - curr_node = curr_node.parent - - return f"{pointer_augmentor}{type_augmentor}{array_augmentor}" - - def __get_comment(self, node: Node) -> str: - """ - Extract the comment associated with a tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter node whose - - Returns - ------- - str - The comment associeted with the given node. - """ - - docs = [] - curr_node = node - while curr_node.prev_named_sibling and curr_node.prev_named_sibling.type == "comment": - curr_node = curr_node.prev_named_sibling - text = curr_node.text.decode() - docs.append(text) - - return "\n".join(reversed(docs)) diff --git a/cldk/analysis/go/__init__.py b/cldk/analysis/go/__init__.py deleted file mode 100644 index 5e39e5c..0000000 --- a/cldk/analysis/go/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Go package -""" diff --git a/cldk/analysis/go/treesitter/__init__.py b/cldk/analysis/go/treesitter/__init__.py deleted file mode 100644 index 4319921..0000000 --- a/cldk/analysis/go/treesitter/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Treesitter package -""" - -from cldk.analysis.go.treesitter.go_sitter import GoSitter - -__all__ = ["GoSitter"] diff --git a/cldk/analysis/go/treesitter/go_sitter.py b/cldk/analysis/go/treesitter/go_sitter.py deleted file mode 100644 index 54f502a..0000000 --- a/cldk/analysis/go/treesitter/go_sitter.py +++ /dev/null @@ -1,471 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -GoSitter module -""" - -from typing import List -from tree_sitter import Language, Parser, Query, Node -import tree_sitter_go as tsgo - -from cldk.models.go.models import GoCallable, GoImport, GoParameter, GoSourceFile -from cldk.models.treesitter import Captures - - -class GoSitter: - """ - Tree sitter for Go use cases. - """ - - def __init__(self) -> None: - self.language: Language = Language(tsgo.language()) - self.parser: Parser = Parser(self.language) - - def get_all_functions(self, code: str) -> List[GoCallable]: - """ - Get all the functions and methods in the provided code. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[GoCallable] - All the function and method details within the provided code. - """ - - query = """ - ((function_declaration) @function) - ((method_declaration) @method) - """ - - callables: List[GoCallable] = [] - captures: Captures = self.__frame_query_and_capture_output(query, code) - for capture in captures: - if capture.name == "function": - callables.append(self.__get_function_details(capture.node)) - elif capture.name == "method": - callables.append(self.__get_method_details(capture.node)) - - return callables - - def get_imports(self, code: str) -> List[GoImport]: - """ - Get all the imports in the provided code. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[GoImport] - All the imports within the provided code. - """ - - query = """ - (import_declaration - (import_spec) @import - ) - - (import_declaration - (import_spec_list - (import_spec) @import - ) - ) - """ - - return [self.__extract_import_details(capture.node) for capture in self.__frame_query_and_capture_output(query, code)] - - def get_source_file_details(self, source_file: str) -> GoSourceFile: - """ - Get the details of the provided source file. - - Parameters - ---------- - source_file : str - The source file code you want to analyse. - - Returns - ------- - GoSourceFile - The details of the provided source file code. - """ - - return GoSourceFile( - imports=self.get_imports(source_file), - callables=self.get_all_functions(source_file), - ) - - def __frame_query_and_capture_output(self, query: str, code_to_process: str) -> Captures: - """Frame a query for the tree-sitter parser. - - Parameters - ---------- - query : str - The query to frame. - code_to_process : str - The code to process. - - Returns - ------- - Captures - The list of tree-sitter captures. - """ - - framed_query: Query = self.language.query(query) - tree = self.parser.parse(bytes(code_to_process, "utf-8")) - return Captures(framed_query.captures(tree.root_node)) - - def __query_node_and_capture_output(self, query: str, node: Node) -> Captures: - """Frame a query for the tree-sitter parser and query the given tree-sitter node. - - Parameters - ---------- - query : str - The query to frame. - node : Node - The root node used for querying. - - Returns - ------- - Captures - The list of tree-sitter captures. - """ - - framed_query: Query = self.language.query(query) - return Captures(framed_query.captures(node)) - - def __get_function_details(self, node: Node) -> GoCallable: - """ - Extract the function details from a tree-sitter function node. - - Parameters - ---------- - node : Node - The tree-sitter function node whose details we want. - - Returns - ------- - GoCallable - The function details. - """ - - name: str = self.__get_name(node) - return GoCallable( - name=name, - signature=self.__get_signature(node), - code=node.text.decode(), - start_line=node.start_point[0], - end_line=node.end_point[0], - modifiers=["public"] if name[0].isupper() else ["private"], - comment=self.__get_comment(node), - parameters=self.__get_parameters(node), - return_types=self.__get_return_types(node), - ) - - def __get_method_details(self, node: Node) -> GoCallable: - """ - Extract the method details from a tree-sitter method node. - - Parameters - ---------- - node : Node - The tree-sitter method node whose details we want. - - Returns - ------- - GoCallable - The method details. - """ - - name: str = self.__get_name(node) - return GoCallable( - name=name, - signature=self.__get_signature(node), - code=node.text.decode(), - start_line=node.start_point[0], - end_line=node.end_point[0], - modifiers=["public"] if name[0].isupper() else ["private"], - comment=self.__get_comment(node), - parameters=self.__get_parameters(node), - return_types=self.__get_return_types(node), - receiver=self.__get_receiver(node), - ) - - def __get_name(self, node: Node) -> str: - """ - Extract the name of a tree-sitter function or method node. - - Parameters - ---------- - node : Node - The tree-sitter node whose name we want. - - Returns - ------- - str - The method/function name. - """ - - return node.child_by_field_name("name").text.decode() - - def __get_signature(self, node: Node) -> str: - """ - Extract the signature of a tree-sitter function or method node. - - Parameters - ---------- - node : Node - The tree-sitter node whose signature we want. - - Returns - ------- - str - The method/function signature. - """ - - signature = "" - # only methods have a receiver - receiver_node: Node = node.child_by_field_name("receiver") - if receiver_node: - signature += receiver_node.text.decode() - - if signature: - signature += " " - - name = self.__get_name(node) - signature += name - - # generics type, optional field available only for functions - type_params_node: Node = node.child_by_field_name("type_parameters") - if type_params_node: - signature += type_params_node.text.decode() - - signature += node.child_by_field_name("parameters").text.decode() - - result_node: Node = node.child_by_field_name("result") - if result_node: - signature += " " + result_node.text.decode() - - return signature - - def __get_comment(self, node: Node) -> str: - """ - Extract the comment associated with a tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter node whose docs we want. - - Returns - ------- - str - The comment associated with the given node. - """ - - docs = [] - curr_node = node - while curr_node.prev_named_sibling and curr_node.prev_named_sibling.type == "comment": - curr_node = curr_node.prev_named_sibling - text = curr_node.text.decode() - docs.append(text) - - return "\n".join(reversed(docs)) - - def __get_parameters(self, node: Node) -> List[GoParameter]: - """ - Extract the parameters from a tree-sitter function/method node. - - Parameters - ---------- - node : Node - The tree-sitter node whose parameters we want. - - Returns - ------- - List[GoParameter] - The list of parameter details. - """ - - parameters_node: Node = node.child_by_field_name("parameters") - if not parameters_node or not parameters_node.children: - return [] - - parameters: List[GoParameter] = [] - for child in parameters_node.children: - if child.type == "parameter_declaration": - parameters.extend(self.__extract_parameters(child)) - elif child.type == "variadic_parameter_declaration": - parameters.append(self.__extract_variadic_parameter(child)) - - return parameters - - def __get_receiver(self, node: Node) -> GoParameter: - """ - Extract the receiver from a tree-sitter method node. - - Parameters - ---------- - node : Node - The tree-sitter node whose receiver we want. - - Returns - ------- - GoParameter - The receiver details. - """ - - receiver_node: Node = node.child_by_field_name("receiver") - - # it must have 1 non-variadic child - for child in receiver_node.children: - if child.type == "parameter_declaration": - return self.__extract_parameters(child)[0] - - def __get_return_types(self, node: Node) -> List[str]: - """ - Extract the return types from a callable tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter node whose types we want. - - Returns - ------- - List[str] - The list of types returned by the callable. Empty list, if it does not return. - """ - - result_node: Node = node.child_by_field_name("result") - if not result_node: - return [] - - if result_node.type == "parameter_list": - return_types: List[str] = [] - for child in result_node.children: - if child.type == "parameter_declaration": - return_types.extend([param.type for param in self.__extract_parameters(child)]) - elif child.type == "variadic_parameter_declaration": - return_types.append(self.__extract_variadic_parameter(child).type) - - return return_types - else: - # TODO: might need to be more specific - return [result_node.text.decode()] - - def __extract_parameters(self, parameter_declaration_node: Node) -> List[GoParameter]: - """ - Extract parameter details from a tree-sitter parameter declaration node. - - Parameters - ---------- - parameter_declaration_node : Node - The tree-sitter node whose details we want. - - Returns - ------- - List[GoParameter] - The list of parameter details. - """ - - type_node: Node = parameter_declaration_node.child_by_field_name("type") - param_type = type_node.text.decode() - is_reference_type = param_type.startswith("*") - - query = """((identifier) @name)""" - captures: Captures = self.__query_node_and_capture_output(query, parameter_declaration_node) - - # name is optional - if len(captures) == 0: - return [ - GoParameter( - type=param_type, - is_reference=is_reference_type, - is_variadic=False, - ) - ] - - return [ - GoParameter( - name=capture.node.text.decode(), - type=param_type, - is_reference=is_reference_type, - is_variadic=False, - ) - for capture in captures - ] - - def __extract_variadic_parameter(self, variadic_parameter_node: Node) -> GoParameter: - """ - Extract parameter details from a tree-sitter variadic declaration node. - - Parameters - ---------- - variadic_parameter_node : Node - The tree-sitter node whose details we want. - - Returns - ------- - GoParameter - The details of the variadic parameter. - """ - - name: str = None - # name is not mandatory - name_node: Node = variadic_parameter_node.child_by_field_name("name") - if name_node: - name = name_node.text.decode() - - type_node: Node = variadic_parameter_node.child_by_field_name("type") - param_type = type_node.text.decode() - - return GoParameter( - name=name, - type="..." + param_type, - is_reference=param_type.startswith("*"), - is_variadic=True, - ) - - def __extract_import_details(self, node: Node) -> GoImport: - """ - Extract the import details from a tree-sitter import spec node. - - Parameters - ---------- - node : Node - The import spec node tree-sitter node whose details we want. - - Returns - ------- - GoImport - The import details. - """ - - name_node: Node = node.child_by_field_name("name") - path_node: Node = node.child_by_field_name("path") - path = path_node.text.decode() - - return GoImport( - name=name_node.text.decode() if name_node else None, - path=path[1 : len(path) - 1], - ) diff --git a/cldk/analysis/javascript/__init__.py b/cldk/analysis/javascript/__init__.py deleted file mode 100644 index 3dbaddb..0000000 --- a/cldk/analysis/javascript/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -JavaScript package -""" diff --git a/cldk/analysis/javascript/treesitter/__init__.py b/cldk/analysis/javascript/treesitter/__init__.py deleted file mode 100644 index db754cb..0000000 --- a/cldk/analysis/javascript/treesitter/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Treesitter package -""" - -from cldk.analysis.javascript.treesitter.javascript_sitter import JavascriptSitter - -__all__ = ["JavascriptSitter"] diff --git a/cldk/analysis/javascript/treesitter/javascript_sitter.py b/cldk/analysis/javascript/treesitter/javascript_sitter.py deleted file mode 100644 index d67505c..0000000 --- a/cldk/analysis/javascript/treesitter/javascript_sitter.py +++ /dev/null @@ -1,477 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -JavascriptSitter module -""" - -from typing import List, Optional -from tree_sitter import Language, Parser, Query, Node -import tree_sitter_javascript as tsjavascript - -from cldk.models.javascript.models import JsCallable, JsClass, JsParameter, JsProgram -from cldk.models.treesitter import Captures - - -class JavascriptSitter: - """ - Tree sitter for Javascript use cases. - """ - - def __init__(self) -> None: - self.language: Language = Language(tsjavascript.language()) - self.parser: Parser = Parser(self.language) - - def get_all_functions(self, code: str) -> List[JsCallable]: - """ - Get all the functions and methods in the provided code. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsCallable] - All the function and method details within the provided code. - """ - - callables: List[JsCallable] = [] - classes: List[JsClass] = self.get_classes(code) - for clazz in classes: - callables.extend(clazz.methods) - - callables.extend(self.__get_top_level_functions(code)) - callables.extend(self.__get_top_level_generators(code)) - callables.extend(self.__get_top_level_arrow_functions(code)) - callables.extend(self.__get_top_level_function_expressions(code)) - callables.extend(self.__get_top_level_generator_expressions(code)) - - return callables - - def get_classes(self, code: str) -> List[JsClass]: - """ - Get the classes in the provided code. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsClass] - All class details within the provided code. - """ - - query = """(class_declaration) @class""" - - return [self.__get_class_details(capture.node) for capture in self.__frame_query_and_capture_output(query, code)] - - def get_program_details(self, source_file: str) -> JsProgram: - """ - Get the details of the provided code file. - - Parameters - ---------- - source_file : str - The code we want to analyse. - - Returns - ------- - The details of the provided file. - """ - - return JsProgram( - classes=self.get_classes(source_file), - callables=self.get_all_functions(source_file), - ) - - def __frame_query_and_capture_output(self, query: str, code_to_process: str) -> Captures: - """Frame a query for the tree-sitter parser. - - Parameters - ---------- - query : str - The query to frame. - code_to_process : str - The code to process. - - Returns - ------- - Captures - The list of tree-sitter captures. - """ - - framed_query: Query = self.language.query(query) - tree = self.parser.parse(bytes(code_to_process, "utf-8")) - return Captures(framed_query.captures(tree.root_node)) - - def __get_class_details(self, node: Node) -> JsClass: - """ - Get the classe details for a provided tree-sitter class node. - - Parameters - ---------- - node : Node - The tree-sitter class node whose details we want. - - Returns - ------- - JsClass - The class details of the provided node. - """ - - parent_node: Node = self.__get_class_parent_node(node) - - return JsClass( - name=node.child_by_field_name("name").text.decode(), - methods=self.__get_methods(node), - start_line=node.start_point[0], - end_line=node.end_point[0], - # TODO: needs more refinement since you can have more than an identifier - parent=parent_node.named_children[0].text.decode() if parent_node else None, - ) - - def __get_methods(self, class_node: Node) -> List[JsCallable]: - """ - Get the methods for a provided tree-sitter class node. - - Parameters - ---------- - class_node : Node - The tree-sitter class node whose methods we want. - - Returns - ------- - List[JsCallable] - The method details of the provided class node. - """ - - class_body_node = class_node.child_by_field_name("body") - - return [self.__extract_function_details(child) for child in class_body_node.children if child.type == "method_definition"] - - def __get_top_level_functions(self, code: str) -> List[JsCallable]: - """ - Get the exportable functions from the provided code. - There is no guarantee that the functions are exported. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsCallable] - The function details within the provided code. - """ - - query = """ - (program [ - (function_declaration) @function - (export_statement (function_declaration) @function.export) - ]) - """ - captures: Captures = self.__frame_query_and_capture_output(query, code) - - return [self.__extract_function_details(capture.node) for capture in captures] - - def __get_top_level_generators(self, code: str) -> List[JsCallable]: - """ - Get the exportable generator functions from the provided code. - There is no guarantee that the functions are exported. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsCallable] - The generator function details within the provided code. - """ - - query = """ - (program [ - (generator_function_declaration) @generator - (export_statement (generator_function_declaration) @generator.export) - ]) - """ - captures: Captures = self.__frame_query_and_capture_output(query, code) - - return [self.__extract_function_details(capture.node) for capture in captures] - - def __get_top_level_arrow_functions(self, code: str) -> List[JsCallable]: - """ - Get the exportable arrow functions from the provided code. - There is no guarantee that the functions are exported. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsCallable] - The arrow function details within the provided code. - """ - - # get arrow functions that can be called from an external file. - query = """ - (program [ - (expression_statement (assignment_expression (arrow_function) @arrow.assignment)) - (expression_statement (sequence_expression (assignment_expression (arrow_function) @arrow.assignment))) - (lexical_declaration (variable_declarator (arrow_function) @arrow.variable)) - (export_statement (arrow_function) @arrow.export) - (export_statement (lexical_declaration (variable_declarator (arrow_function) @arrow.export.variable))) - ]) - """ - - captures: Captures = self.__frame_query_and_capture_output(query, code) - callables: List[JsCallable] = [self.__extract_arrow_function_details(capture.node, capture.name) for capture in captures] - - return [callable for callable in callables if callable.name] - - def __get_top_level_function_expressions(self, code: str) -> List[JsCallable]: - """ - Get the exportable function expressions from the provided code. - There is no guarantee that the functions are exported. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsCallable] - The function expression details within the provided code. - """ - - # get function expressions that can be called from an external file. - # TODO: function node changed to function_expression in newer tree-sitter versions - query = """ - (program [ - (expression_statement (assignment_expression (function) @function.assignment)) - (expression_statement (sequence_expression (assignment_expression (function) @function.assignment))) - (lexical_declaration (variable_declarator (function) @function.variable)) - (export_statement (function) @function.export) - (export_statement (lexical_declaration (variable_declarator (function) @function.export.variable))) - ]) - """ - - captures: Captures = self.__frame_query_and_capture_output(query, code) - - return [self.__extract_function_expression_details(capture.node, capture.name) for capture in captures] - - def __get_top_level_generator_expressions(self, code: str) -> List[JsCallable]: - """ - Get the exportable generator expressions from the provided code. - There is no guarantee that the functions are exported. - - Parameters - ---------- - code : str - The code you want to analyse. - - Returns - ------- - List[JsCallable] - The generator expression details within the provided code. - """ - - # get generator expressions that can be called from an external file. - query = """ - (program [ - (expression_statement (assignment_expression (generator_function) @function.assignment)) - (expression_statement (sequence_expression (assignment_expression (generator_function) @function.assignment))) - (lexical_declaration (variable_declarator (generator_function) @function.variable)) - (export_statement (generator_function) @function.export) - (export_statement (lexical_declaration (variable_declarator (generator_function) @function.export.variable))) - ]) - """ - - captures: Captures = self.__frame_query_and_capture_output(query, code) - - return [self.__extract_function_expression_details(capture.node, capture.name) for capture in captures] - - def __extract_function_details(self, function_node: Node) -> JsCallable: - """ - Extract the details from a function/method tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter function node whose details we want. - capture_name : str - The identifier used to extract the node. - - Returns - ------- - JsCallable - The function details. - """ - - name: str = function_node.child_by_field_name("name").text.decode() - parameters_node: Node = function_node.child_by_field_name("parameters") - - return JsCallable( - name=name, - code=function_node.text.decode(), - paremeters=self.__extract_parameters_details(parameters_node), - signature=name + parameters_node.text.decode(), - start_line=function_node.start_point[0], - end_line=function_node.end_point[0], - is_constructor=function_node.type == "method_definition" and name == "constructor", - ) - - def __extract_arrow_function_details(self, node: Node, capture_name: str) -> JsCallable: - """ - Extract the details from an arrow function tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter arrow function node whose details we want. - capture_name : str - The identifier used to extract the node. - - Returns - ------- - JsCallable - The function details. - """ - - name: str = None - if capture_name == "arrow.assignment": - left_node = node.parent.child_by_field_name("left") - if left_node.type == "identifier": - name = left_node.text.decode() - elif capture_name == "arrow.export": - name = "default" - else: - name_node = node.parent.child_by_field_name("name") - name = name_node.text.decode() - - parameter_node: Node = node.child_by_field_name("parameter") - parameters_node: Node = node.child_by_field_name("parameters") - - # TODO: not sure about this - parameters_text = f"({parameter_node.text.decode()})" if parameter_node else parameters_node.text.decode() - signature: str = (name if name else "") + parameters_text - - return JsCallable( - name=name, - code=node.text.decode(), - paremeters=[JsParameter(name=parameter_node.text.decode())] if parameter_node else self.__extract_parameters_details(parameters_node), - signature=signature, - start_line=node.start_point[0], - end_line=node.end_point[0], - ) - - def __extract_function_expression_details(self, node: Node, capture_name: str) -> JsCallable: - """ - Extract the details from a function expression tree-sitter node. - - Parameters - ---------- - node : Node - The tree-sitter function node whose details we want. - capture_name : str - The identifier used to extract the node. - - Returns - ------- - JsCallable - The function details. - """ - - name: str = None - if capture_name == "function.assignment": - left_node = node.parent.child_by_field_name("left") - if left_node.type == "identifier": - name = left_node.text.decode() - elif capture_name == "function.export": - name = "default" - else: - name_node = node.parent.child_by_field_name("name") - name = name_node.text.decode() - - parameters_node: Node = node.child_by_field_name("parameters") - - # TODO: not sure about this - signature: str = (name if name else "") + parameters_node.text.decode() - - return JsCallable( - name=name, - code=node.text.decode(), - paremeters=self.__extract_parameters_details(parameters_node), - signature=signature, - start_line=node.start_point[0], - end_line=node.end_point[0], - ) - - def __extract_parameters_details(self, parameters_node: Node) -> List[JsParameter]: - """ - Extract the parameter details from a given tree-sitter parameters node. - - Parameters - ---------- - parameters_node : Node - The tree-sitter parameters node whose details we want. - - Returns - ------- - List[JsParameter] - The list of parameter details. - """ - - if not parameters_node or not parameters_node.children: - return [] - - parameters: List[JsParameter] = [] - for child in parameters_node.children: - # TODO incomplete, needs a recursive way of finding the parameters - if child.type in ["identifier", "undefined"]: - parameters.append(JsParameter(name=child.text.decode())) - - return parameters - - def __get_class_parent_node(self, class_node: Node) -> Optional[Node]: - """ - Extracts the tree-sitter heritage node, if it exists from a class node. - - Parameters - ---------- - class_node : Node - The tree-sitter class node we want to process. - - Returns - ------- - Optional[Node] - The tree-sitter node that has the heritage data for the provided class node. - """ - - for child in class_node.children: - if child.type == "class_heritage": - return child - - return None diff --git a/cldk/models/c/__init__.py b/cldk/models/c/__init__.py deleted file mode 100644 index a47394b..0000000 --- a/cldk/models/c/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -C package -""" diff --git a/cldk/models/c/models.py b/cldk/models/c/models.py deleted file mode 100644 index 8419e52..0000000 --- a/cldk/models/c/models.py +++ /dev/null @@ -1,131 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Models module -""" - -from typing import List, Optional -from pydantic import BaseModel - - -class COutput(BaseModel): - """ - Represents the output of a C function. - - Parameters - ---------- - type : str - The type of the output. - qualifiers : List[str] - The list of type qualifiers. E.g.: const, volatile, restrict, etc. - is_reference : bool - A flag indicating whether the output is a pointer. - """ - - type: str - # Type qualifiers: const, volatile, restrict, etc. - qualifiers: List[str] - is_reference: bool - - -class CParameter(COutput): - """ - Represents a parameter in a C function. - - Parameters - ---------- - name : str - The name of the parameter. - specifiers : List[str] - The list of storage class specifiers. E.g.: auto, register, static, extern, etc. - """ - - name: str - # Storage-class specifiers: auto, register, static, extern, etc. - specifiers: List[str] - - -class CFunction(BaseModel): - """ - Represents a function in C. - - Parameters - ---------- - name : str - The name of the function. - signature : str - The signature of the function. - comment : Optional[str] - The comment associated with the function. - parameters : List[CParameter] - The parameters of the function. - output : COutput - The return of the function. - code : str - The code block of the callable. - start_line : int - The starting line number of the callable in the source file. - end_line : int - The ending line number of the callable in the source file. - specifiers : List[str] - The list of storage class specifiers. E.g.: auto, register, static, extern, etc. - """ - - name: str - signature: str - code: str - start_line: int - end_line: int - parameters: List[CParameter] - output: COutput - comment: Optional[str] - # Storage-class specifiers: auto, register, static, extern, etc. - specifiers: List[str] - - -class CImport(BaseModel): - """ - Represents a C import. - - Parameters - ---------- - value : str - The name or path of file being imported. - is_system : bool - A flag indicating whether the import is a system one. - """ - - value: str - is_system: bool - - -class CTranslationUnit(BaseModel): - """ - Represents the content of a C file. - - Parameters - ---------- - imports : List[CImport] - The list of imports present inside the file. - functions : List[CFunction] - The functions defined inside the file. - """ - - imports: List[CImport] - functions: List[CFunction] - - # TODO: type definitions, structs diff --git a/cldk/models/go/__init__.py b/cldk/models/go/__init__.py deleted file mode 100644 index 5e39e5c..0000000 --- a/cldk/models/go/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Go package -""" diff --git a/cldk/models/go/models.py b/cldk/models/go/models.py deleted file mode 100644 index 4d5ce7c..0000000 --- a/cldk/models/go/models.py +++ /dev/null @@ -1,121 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Models module -""" - -from typing import List, Optional -from pydantic import BaseModel - - -class GoParameter(BaseModel): - """ - Represents a function/method parameter in Go. - - Parameters - ---------- - name : Optional[str] - The name of the parameter. If the parameter is not referenced, the name can be omitted. - type : str - The type of the parameter. - is_reference : bool - A flag indicating whether the type is a pointer. - is_variadic : bool - A flag indicating whether the parameter is variadic. - """ - - # Go allows parameters without name, they can't be used - name: Optional[str] = None - type: str - is_reference: bool - is_variadic: bool - - -class GoImport(BaseModel): - """ - Represents an import in Go. - - Parameters - ---------- - path : str - The path to the imported package. - name : Optional[str] - The alias of the imported package. Useful when the implicit name is - too long or to avoid package name clashes. - """ - - path: str - name: Optional[str] = None - - -class GoCallable(BaseModel): - """ - Represents a callable entity such as a method or function in Go. - - Parameters - ---------- - name : str - The name of the callable. - signature : str - The signature of the callable. - comment : str - The comment associated with the callable. - modifiers : List[str] - The modifiers applied to the callable (e.g., public, static). - parameters : List[GoParameter] - The parameters of the callable. - return_types : List[str] - The list of return type of the callable. Empty list, if the callable does not return a value. - receiver : Optional[GoParameter] - The callable's associated type. Only applicable for methods. - code : str - The code block of the callable. - start_line : int - The starting line number of the callable in the source file. - end_line : int - The ending line number of the callable in the source file. - """ - - name: str - signature: str - comment: str - modifiers: List[str] - parameters: List[GoParameter] - # only methods have a receiver - receiver: Optional[GoParameter] = None - return_types: List[str] - code: str - start_line: int - end_line: int - - -class GoSourceFile(BaseModel): - """ - Represents a source file in Go. - - Parameters - ---------- - imports : List[GoImport] - The list of imports present in the source file. - callables : List[GoCallable] - The list of callable entities present in the source file. - """ - - imports: List[GoImport] - callables: List[GoCallable] - - # TODO: types diff --git a/cldk/models/javascript/__init__.py b/cldk/models/javascript/__init__.py deleted file mode 100644 index 80ff8b4..0000000 --- a/cldk/models/javascript/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -JavaScript package -""" - -from .models import JsParameter, JsCallable, JsClass, JsProgram - -__all__ = ["JsParameter", "JsCallable", "JsClass", "JsProgram"] diff --git a/cldk/models/javascript/models.py b/cldk/models/javascript/models.py deleted file mode 100644 index bfa168d..0000000 --- a/cldk/models/javascript/models.py +++ /dev/null @@ -1,115 +0,0 @@ -################################################################################ -# Copyright IBM Corporation 2024 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -################################################################################ - -""" -Models module -""" - -from typing import List, Optional -from pydantic import BaseModel - - -class JsParameter(BaseModel): - """ - Represents a function/method parameter in Javascript. - - Parameters - ---------- - name : str - The name of the parameter. - default_value : Optional[str] - The default value of the parameter, used when a value is not provided. - is_rest : bool - A flag indicating whether the parameter is a rest parameter. - """ - - name: str - default_value: Optional[str] = None - is_rest: bool = False - # type Optional[str] - might be able to extract from JsDoc - - -class JsCallable(BaseModel): - """ - Represents a callable entity such as a method or function in Javascript. - - Parameters - ---------- - name : str - The name of the callable. - signature : str - The signature of the callable. - parameters : List[JsParameter] - The parameters of the callable. - code : str - The code block of the callable. - start_line : int - The starting line number of the callable in the source file. - end_line : int - The ending line number of the callable in the source file. - is_constructor : bool - A flag indicating whether the callable is a constructor. - """ - - name: str - code: str - signature: str - paremeters: List[JsParameter] - start_line: int - end_line: int - is_constructor: bool = False - - -class JsClass(BaseModel): - """ - Represents a class in Javascript. - - Parameters - ---------- - name : str - The name of the class. - methods : List[JsCallable] - The methods of the class. - start_line : int - The starting line number of the class in the source file. - end_line : int - The ending line number of the class in the source file. - parent : Optional[str] - The name of the parent class. - """ - - name: str - methods: List[JsCallable] - parent: Optional[str] = None - start_line: int - end_line: int - - -class JsProgram(BaseModel): - """ - Represents a source file in Javascript. - - Parameters - ---------- - classes : List[JsClass] - The list of classes present in the source file. - callables : List[JsCallable] - The list of callable entities present in the source file. - """ - - classes: List[JsClass] - callables: List[JsCallable] - # TODO: imports diff --git a/tests/tree_sitter/python/test_python_tree_sitter.py b/tests/tree_sitter/python/test_python_tree_sitter.py index 4fb4b81..9f8d932 100644 --- a/tests/tree_sitter/python/test_python_tree_sitter.py +++ b/tests/tree_sitter/python/test_python_tree_sitter.py @@ -1,177 +1,177 @@ -from unittest import TestCase - -from cldk.analysis.python.treesitter import PythonSitter - - -class TestPythonTreeSitter(TestCase): - """ - Tests for Python TreeSitter nodule - """ - - def setUp(self): - """Runs before each test case""" - self.python_tree_sitter = PythonSitter() - - def tearDown(self): - """Runs after each test case""" - - def test_is_parasable(self): - module_str = """ - @staticmethod - def foo() -> None: - pass - class Person: - def __init__(self, name: str, age: int): - self.name = name - self.age = age - @staticmethod - def __str__(self):" - """ - self.assertFalse(self.python_tree_sitter.is_parsable(module_str)) - - def test_get_all_methods(self): - module_str = """ - @staticmethod - def foo() -> None: - pass - class Person: - def __init__(self, name: str, age: int): - self.name = name - self.age = age - @staticmethod - def __str__(self): - return f"{self.name}({self.age})" - """ - all_methods = self.python_tree_sitter.get_all_methods(module=module_str) - all_functions = self.python_tree_sitter.get_all_functions(module=module_str) - self.assertEquals(len(all_methods), 2) - self.assertEquals(len(all_functions), 1) - self.assertEquals(all_methods[0].full_signature, "__init__(self, name: str, age: int)") - self.assertTrue(all_methods[0].is_constructor) - self.assertFalse(all_methods[0].is_static) - self.assertEquals(all_methods[0].class_signature, "Person") - self.assertEquals(all_functions[0].class_signature, "") - self.assertFalse(all_functions[0].is_static) - - def test_get_all_imports(self): - module_str = """ - from typing import List - - from sphinx.domains.python import PyField - from tree_sitter import Language, Parser, Query, Node - import a - @staticmethod - def foo() -> None: - pass - class Person: - def __init__(self, name: str, age: int): - self.name = name - self.age = age - @staticmethod - def __str__(self): - return f"{self.name}({self.age})" - """ - all_imports = self.python_tree_sitter.get_all_imports(module=module_str) - self.assertEquals(len(all_imports), 4) - - def test_get_all_imports_details(self): - module_str = """ - from typing import List - - from sphinx.domains.python import PyField - from tree_sitter import Language, Parser, Query, Node - import a - @staticmethod - def foo() -> None: - pass - class Person: - def __init__(self, name: str, age: int): - self.name = name - self.age = age - @staticmethod - def __str__(self): - return f"{self.name}({self.age})" - """ - all_imports = self.python_tree_sitter.get_all_imports_details(module=module_str) - self.assertEquals(len(all_imports), 4) - - def test_get_module(self): - module_str = """ - from typing import List - - from sphinx.domains.python import PyField - from tree_sitter import Language, Parser, Query, Node - import a - @staticmethod - def foo() -> None: - pass - class Person: - def __init__(self, name: str, age: int): - self.name = name - self.age = age - @staticmethod - def __str__(self): - return f"{self.name}({self.age})" - """ - module_details = self.python_tree_sitter.get_module_details(module=module_str) - self.assertIsNotNone(module_details.functions) - self.assertIsNotNone(module_details.classes) - self.assertIsNotNone(module_details.imports) - - def test_get_all_classes(self): - module_str = """ - def foo() -> None: - pass - class Person: - def __init__(self, name: str, age: int): - self.name = name - self.age = age - - def __str__(self): - return f"{self.name}({self.age})" - """ - all_classes = self.python_tree_sitter.get_all_classes(module=module_str) - self.assertEquals(len(all_classes), 1) - self.assertEquals(len(all_classes[0].methods), 2) - self.assertEquals(all_classes[0].methods[0].full_signature, "__init__(self, name: str, age: int)") - self.assertEquals(all_classes[0].methods[1].class_signature, "Person") - - def test_get_all_test_classes(self): - module_str = """ - import unittest - - class TestStringMethods(unittest.TestCase, ABC): - - def test_upper(self): - self.assertEqual('foo'.upper(), 'FOO') - - def test_isupper(self): - self.assertTrue('FOO'.isupper()) - self.assertFalse('Foo'.isupper()) - - def test_split(self): - s = 'hello world' - self.assertEqual(s.split(), ['hello', 'world']) - # check that s.split fails when the separator is not a string - with self.assertRaises(TypeError): - s.split(2) - - if __name__ == '__main__': - unittest.main() - """ - all_classes = self.python_tree_sitter.get_all_classes(module=module_str) - self.assertTrue(all_classes[0].is_test_class) - - def test_call_site(self): - module_str = """ - import unittest - - class TestStringMethods(unittest.TestCase, ABC): - - def test_get_all_test_classes(self): - module_str = "a" - all_classes = self.python_tree_sitter.get_all_classes(module=module_str) - self.assertTrue(all_classes[0].is_test_class) - """ - all_classes = self.python_tree_sitter.get_all_classes(module=module_str) - self.assertTrue(all_classes[0].is_test_class) +# from unittest import TestCase + +# from cldk.analysis.python.treesitter import PythonSitter + + +# class TestPythonTreeSitter(TestCase): +# """ +# Tests for Python TreeSitter nodule +# """ + +# def setUp(self): +# """Runs before each test case""" +# self.python_tree_sitter = PythonSitter() + +# def tearDown(self): +# """Runs after each test case""" + +# def test_is_parasable(self): +# module_str = """ +# @staticmethod +# def foo() -> None: +# pass +# class Person: +# def __init__(self, name: str, age: int): +# self.name = name +# self.age = age +# @staticmethod +# def __str__(self):" +# """ +# self.assertFalse(self.python_tree_sitter.is_parsable(module_str)) + +# def test_get_all_methods(self): +# module_str = """ +# @staticmethod +# def foo() -> None: +# pass +# class Person: +# def __init__(self, name: str, age: int): +# self.name = name +# self.age = age +# @staticmethod +# def __str__(self): +# return f"{self.name}({self.age})" +# """ +# all_methods = self.python_tree_sitter.get_all_methods(module=module_str) +# all_functions = self.python_tree_sitter.get_all_functions(module=module_str) +# self.assertEquals(len(all_methods), 2) +# self.assertEquals(len(all_functions), 1) +# self.assertEquals(all_methods[0].full_signature, "__init__(self, name: str, age: int)") +# self.assertTrue(all_methods[0].is_constructor) +# self.assertFalse(all_methods[0].is_static) +# self.assertEquals(all_methods[0].class_signature, "Person") +# self.assertEquals(all_functions[0].class_signature, "") +# self.assertFalse(all_functions[0].is_static) + +# def test_get_all_imports(self): +# module_str = """ +# from typing import List + +# from sphinx.domains.python import PyField +# from tree_sitter import Language, Parser, Query, Node +# import a +# @staticmethod +# def foo() -> None: +# pass +# class Person: +# def __init__(self, name: str, age: int): +# self.name = name +# self.age = age +# @staticmethod +# def __str__(self): +# return f"{self.name}({self.age})" +# """ +# all_imports = self.python_tree_sitter.get_all_imports(module=module_str) +# self.assertEquals(len(all_imports), 4) + +# def test_get_all_imports_details(self): +# module_str = """ +# from typing import List + +# from sphinx.domains.python import PyField +# from tree_sitter import Language, Parser, Query, Node +# import a +# @staticmethod +# def foo() -> None: +# pass +# class Person: +# def __init__(self, name: str, age: int): +# self.name = name +# self.age = age +# @staticmethod +# def __str__(self): +# return f"{self.name}({self.age})" +# """ +# all_imports = self.python_tree_sitter.get_all_imports_details(module=module_str) +# self.assertEquals(len(all_imports), 4) + +# def test_get_module(self): +# module_str = """ +# from typing import List + +# from sphinx.domains.python import PyField +# from tree_sitter import Language, Parser, Query, Node +# import a +# @staticmethod +# def foo() -> None: +# pass +# class Person: +# def __init__(self, name: str, age: int): +# self.name = name +# self.age = age +# @staticmethod +# def __str__(self): +# return f"{self.name}({self.age})" +# """ +# module_details = self.python_tree_sitter.get_module_details(module=module_str) +# self.assertIsNotNone(module_details.functions) +# self.assertIsNotNone(module_details.classes) +# self.assertIsNotNone(module_details.imports) + +# def test_get_all_classes(self): +# module_str = """ +# def foo() -> None: +# pass +# class Person: +# def __init__(self, name: str, age: int): +# self.name = name +# self.age = age + +# def __str__(self): +# return f"{self.name}({self.age})" +# """ +# all_classes = self.python_tree_sitter.get_all_classes(module=module_str) +# self.assertEquals(len(all_classes), 1) +# self.assertEquals(len(all_classes[0].methods), 2) +# self.assertEquals(all_classes[0].methods[0].full_signature, "__init__(self, name: str, age: int)") +# self.assertEquals(all_classes[0].methods[1].class_signature, "Person") + +# def test_get_all_test_classes(self): +# module_str = """ +# import unittest + +# class TestStringMethods(unittest.TestCase, ABC): + +# def test_upper(self): +# self.assertEqual('foo'.upper(), 'FOO') + +# def test_isupper(self): +# self.assertTrue('FOO'.isupper()) +# self.assertFalse('Foo'.isupper()) + +# def test_split(self): +# s = 'hello world' +# self.assertEqual(s.split(), ['hello', 'world']) +# # check that s.split fails when the separator is not a string +# with self.assertRaises(TypeError): +# s.split(2) + +# if __name__ == '__main__': +# unittest.main() +# """ +# all_classes = self.python_tree_sitter.get_all_classes(module=module_str) +# self.assertTrue(all_classes[0].is_test_class) + +# def test_call_site(self): +# module_str = """ +# import unittest + +# class TestStringMethods(unittest.TestCase, ABC): + +# def test_get_all_test_classes(self): +# module_str = "a" +# all_classes = self.python_tree_sitter.get_all_classes(module=module_str) +# self.assertTrue(all_classes[0].is_test_class) +# """ +# all_classes = self.python_tree_sitter.get_all_classes(module=module_str) +# self.assertTrue(all_classes[0].is_test_class)