Current section

Files

Jump to
igniter_js lib igniter_js parsers javascript parser.ex
Raw

lib/igniter_js/parsers/javascript/parser.ex

defmodule IgniterJs.Parsers.Javascript.Parser do
@moduledoc """
Codemods for JavaScript files.
"""
alias IgniterJs.Native
import IgniterJs.Helpers, only: [call_nif_fn: 4]
@doc """
Check if a module is imported in the given file or content or content and returns boolean.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.module_imported?(js_content, "module")
Parser.module_imported?(js_content, "module", :content)
Parser.module_imported?("/path/to/file.js", "module", :path)
```
"""
def module_imported?(file_path_or_content, module, type \\ :content) do
elem(module_imported(file_path_or_content, module, type), 0) == :ok
end
@doc """
Check if a module is imported in the given file or content or contents and return tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.module_imported(js_content, "module")
Parser.module_imported(js_content, "module", :content)
Parser.module_imported("/path/to/file.js", "module", :path)
```
"""
def module_imported(file_path_or_content, module, type \\ :content) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.is_module_imported_from_ast_nif(file_content, module)
end,
type
)
end
@doc """
Insert imports to the given file or content and returns tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.insert_imports(js_content, imports_lines)
Parser.insert_imports(js_content, imports_lines, :content)
Parser.insert_imports("/path/to/file.js", imports_lines, :path)
```
"""
def insert_imports(file_path_or_content, imports_lines, type \\ :content) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.insert_import_to_ast_nif(file_content, imports_lines)
end,
type
)
end
@doc """
Remove imports from the given file or content. it accepts a single module or a list of modules.
It returns a tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.remove_imports(js_content, "SomeModule")
Parser.remove_imports("/path/to/file.js", "SomeModule", :path)
```
"""
def remove_imports(file_path_or_content, module, type \\ :content)
def remove_imports(file_path_or_content, modules, type) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.remove_import_from_ast_nif(file_content, modules)
end,
type
)
end
@doc """
Check if a LiveSocket var exists in the given file or content and returns boolean.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.exist_live_socket?(js_content)
Parser.exist_live_socket?(js_content, :content)
Parser.exist_live_socket?("/path/to/file.js", :path)
```
"""
def exist_live_socket?(file_path_or_content, type \\ :content) do
elem(exist_live_socket(file_path_or_content, type), 0) == :ok
end
@doc """
Check if a LiveSocket var exists in the given file or content and returns tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.exist_live_socket(js_content)
Parser.exist_live_socket(js_content, :content)
Parser.exist_live_socket("/path/to/file.js", :path)
```
"""
def exist_live_socket(file_path_or_content, type \\ :content) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.find_live_socket_node_from_ast_nif(file_content)
end,
type
)
end
@doc """
Check if a specific var exists in the given file or content and returns boolean.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.exist_live_socket?(js_content)
Parser.exist_live_socket?(js_content, :content)
Parser.exist_live_socket?("/path/to/file.js", :path)
```
"""
def var_exists?(file_path_or_content, type \\ :content) do
elem(exist_var(file_path_or_content, type), 0) == :ok
end
@doc """
Check if an specific var exists in the given file or content and returns tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.exist_live_socket(js_content, var_name)
Parser.exist_live_socket(js_content, var_name, :content)
Parser.exist_live_socket("/path/to/file.js", var_name, :path)
```
"""
def exist_var(file_path_or_content, var_name, type \\ :content) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.contains_variable_from_ast_nif(file_content, var_name)
end,
type
)
end
@doc """
Extend the hook object in the given file or content. It accepts a single object
or a list of objects.
It returns a tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.extend_hook_object(js_content, "SomeObject")
Parser.extend_hook_object(js_content, ["SomeObject", "AnotherObject"], :content)
Parser.extend_hook_object("/path/to/file.js", "SomeObject", :path)
```
"""
def extend_hook_object(file_path_or_content, object_name, type \\ :content)
def extend_hook_object(file_path_or_content, object_name, type) when is_binary(object_name) do
extend_hook_object(file_path_or_content, [object_name], type)
end
def extend_hook_object(file_path_or_content, objects_names, type) when is_list(objects_names) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.extend_hook_object_to_ast_nif(file_content, objects_names)
end,
type
)
end
@doc """
Remove objects from the hooks in the given file or content. It accepts a single o
bject or a list of objects.
It returns a tuple.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.remove_objects_from_hooks(js_content, "SomeObject")
Parser.remove_objects_from_hooks(js_content, ["SomeObject", "AnotherObject"], :content)
Parser.remove_objects_from_hooks("/path/to/file.js", "SomeObject", :path)
```
"""
def remove_objects_from_hooks(file_path_or_content, object_name, type \\ :content)
def remove_objects_from_hooks(file_path_or_content, object_name, type)
when is_binary(object_name) do
remove_objects_from_hooks(file_path_or_content, [object_name], type)
end
def remove_objects_from_hooks(file_path_or_content, objects_names, type)
when is_list(objects_names) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.remove_objects_of_hooks_from_ast_nif(file_content, objects_names)
end,
type
)
end
@doc """
Retrieve statistical information about the JavaScript source code, such as the number of
functions, classes, debugger statements, imports, try-catch blocks, and throw statements.
This function accepts either the content of the JavaScript file or the path to the file,
and returns a tuple with the status, function atom, and the extracted data as a map.
## Examples
```elixir
alias IgniterJs.Parsers.Javascript.Parser
# Analyze a JavaScript source file by providing its content
Parser.statistics(js_content)
# Analyze a JavaScript source file by providing its file path
Parser.statistics("/path/to/file.js", :path)
```
"""
def statistics(file_path_or_content, type \\ :content) do
{status, fn_atom, {_, data}} =
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.statistics_from_ast_nif(file_content)
end,
type
)
converted = if is_map(data), do: Map.drop(data, [:__struct__]), else: data
{status, fn_atom, converted}
end
@doc """
Extend a variable of object type in the given file or content by adding additional objects to it,
based on their names.
This function ensures that duplicate entries are not added during the process.
This function accepts:
- The content or path of the JavaScript file.
- The name of the variable to be extended.
- A single object name or a list of object names to be added.
- The type indicating whether it's content (`:content`) or a path (`:path`).
It returns a tuple with the status, function atom, and the updated content or an error message
if the variable could not be found or modified.
## Examples
```elixir
alias IgniterJs.Parsers.Javascript.Parser
objects_names = ["OXCTestHook", "MishkaHooks", "MishkaHooks", "OXCTestHook"]
Parser.extend_var_object_by_object_names(js_content, "Components", "TestHook")
Parser.extend_var_object_by_object_names("/path/to/file.js", "Components", objects_names, :path)
{:error, :extend_var_object_by_object_names, _output} =
Parser.extend_var_object_by_object_names("None", "Components", objects_names)
```
"""
def extend_var_object_by_object_names(file_path_or_content, var, object_names, type \\ :content)
def extend_var_object_by_object_names(file_path_or_content, var, object_name, type)
when is_binary(object_name) do
extend_var_object_by_object_names(file_path_or_content, var, [object_name], type)
end
def extend_var_object_by_object_names(file_path_or_content, var, object_names, type) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.extend_var_object_property_by_names_to_ast_nif(file_content, var, object_names)
end,
type
)
end
@doc """
Converts a JavaScript AST into the ESTree format.
This function takes either a file path or raw JavaScript content, processes it
and returns the resulting ESTree Map structure.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
Parser.ast_to_estree(js_content)
Parser.ast_to_estree("/path/to/file.js", :path)
```
"""
def ast_to_estree(file_path_or_content, type \\ :content) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.convert_ast_to_estree_nif(file_content)
end,
type
)
|> case do
{:ok, _, output} ->
{:ok, :ast_to_estree, Jason.decode!(output)}
{:error, :ast_to_estree, error} ->
{:error, :ast_to_estree, error}
end
end
@doc """
Inserts a JavaScript AST at the specified index within an existing AST.
This function takes either a file path or raw JavaScript content, along with the
JavaScript code to be inserted and the target index. It processes the AST and inserts
the new code at the specified position.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
# Insert after index 1
Parser.insert_at_index(js_content, "function newFunc() {}", 1)
# Insert before all code
Parser.insert_at_index(js_content, "function newFunc() {}", 0)
# Insert using a file path
Parser.insert_at_index("/path/to/file.js", "function newFunc() {}", 2, :path)
```
"""
def insert_at_index(
file_path_or_content,
insert_code,
index,
type \\ :content
) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.insert_ast_at_index_nif(file_content, insert_code, index)
end,
type
)
end
@doc """
Replaces a JavaScript AST node at the specified index with new JavaScript code.
This function takes either a file path or raw JavaScript content, along with the
JavaScript code that should replace an existing node at the given index. It processes
the AST and replaces the target node while preserving the surrounding structure.
If the `index` is out of bounds, an error is returned.
```elixir
alias IgniterJs.Parsers.Javascript.Parser
# Replace node at index 1
Parser.replace_at_index(js_content, "function newFunc() {}", 1)
# Replace node at index 0 (first item)
Parser.replace_at_index(js_content, "function newFunc() {}", 0)
# Replace using a file path
Parser.replace_at_index("/path/to/file.js", "function newFunc() {}", 2, :path)
```
"""
def replace_at_index(
file_path_or_content,
replace_code,
index,
type \\ :content
) do
call_nif_fn(
file_path_or_content,
__ENV__.function,
fn file_content ->
Native.replace_ast_at_index_nif(file_content, replace_code, index)
end,
type
)
end
end