feat: Commit initially
This commit is contained in:
commit
c451ae5a37
13 changed files with 691 additions and 0 deletions
4
.formatter.exs
Normal file
4
.formatter.exs
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
53
.github/workflows/main.yml
vendored
Normal file
53
.github/workflows/main.yml
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
MIX_ENV: test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- pair:
|
||||
elixir: '1.11'
|
||||
otp: 22
|
||||
- pair:
|
||||
elixir: '1.14'
|
||||
otp: 25
|
||||
lint: lint
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: ${{matrix.pair.otp}}
|
||||
elixir-version: ${{matrix.pair.elixir}}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: deps
|
||||
key: mix-deps-${{ hashFiles('**/mix.lock') }}
|
||||
|
||||
- run: mix deps.get
|
||||
|
||||
- run: mix format --check-formatted
|
||||
if: ${{ matrix.lint }}
|
||||
|
||||
- run: mix deps.unlock --check-unused
|
||||
if: ${{ matrix.lint }}
|
||||
|
||||
- run: mix deps.compile
|
||||
|
||||
- run: mix compile --warnings-as-errors
|
||||
if: ${{ matrix.lint }}
|
||||
|
||||
- run: mix test
|
||||
if: ${{ ! matrix.lint }}
|
||||
|
||||
- run: mix test --warnings-as-errors
|
||||
if: ${{ matrix.lint }}
|
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
tree_sitter-*.tar
|
||||
|
||||
# Temporary files, for example, from tests.
|
||||
/tmp/
|
22
LICENSE.md
Normal file
22
LICENSE.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# MIT License
|
||||
|
||||
Copyright (c) 2023 Robert Prehn.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
39
README.md
Normal file
39
README.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# TreeSitter
|
||||
|
||||
Mix tasks for installing and invoking [tree-sitter](https://tree-sitter.github.io/tree-sitter/).
|
||||
|
||||
## Installation
|
||||
|
||||
If you are going to build assets in production, then you add
|
||||
`tree_sitter` as dependency on all environments but only start it
|
||||
in dev:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:tree_sitter, "~> 0.1.1"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Once installed, change your `config/config.exs` and [pick a version
|
||||
for the tree_sitter CLI](https://github.com/tree-sitter/tree-sitter/releases) of your choice:
|
||||
|
||||
```elixir
|
||||
config :tree_sitter, version: "0.20.8"
|
||||
```
|
||||
|
||||
Now you can install tree_sitter by running:
|
||||
|
||||
```bash
|
||||
$ mix tree_sitter.install
|
||||
```
|
||||
|
||||
The executable is kept at `_build/tree_sitter-TARGET`.
|
||||
Where `TARGET` is your system target architecture.
|
||||
|
||||
# License
|
||||
|
||||
Copyright (c) 2023 Robert Prehn.
|
||||
|
||||
tree_sitter source code is licensed under the [MIT License](LICENSE.md).
|
3
config/config.exs
Normal file
3
config/config.exs
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Config
|
||||
|
||||
config :tree_sitter, version: "0.20.8"
|
60
lib/mix/tasks/tree_sitter.ex
Normal file
60
lib/mix/tasks/tree_sitter.ex
Normal file
|
@ -0,0 +1,60 @@
|
|||
defmodule Mix.Tasks.TreeSitter do
|
||||
@moduledoc """
|
||||
Invokes tree_sitter with the given args.
|
||||
|
||||
Usage:
|
||||
|
||||
$ mix tree_sitter TASK_OPTIONS PROFILE TREE_SITTER_ARGS
|
||||
|
||||
Example:
|
||||
|
||||
$ mix tree_sitter default assets/js/app.js --bundle --minify --target=es2016 --outdir=priv/static/assets
|
||||
|
||||
If tree_sitter is not installed, it is automatically downloaded.
|
||||
Note the arguments given to this task will be appended
|
||||
to any configured arguments.
|
||||
|
||||
## Options
|
||||
|
||||
* `--runtime-config` - load the runtime configuration
|
||||
before executing command
|
||||
|
||||
Note flags to control this Mix task must be given before the
|
||||
profile:
|
||||
|
||||
$ mix tree_sitter --runtime-config default assets/js/app.js
|
||||
|
||||
"""
|
||||
|
||||
@shortdoc "Invokes tree_sitter with the profile and args"
|
||||
@compile {:no_warn_undefined, Mix}
|
||||
|
||||
use Mix.Task
|
||||
|
||||
@impl true
|
||||
def run(args) do
|
||||
switches = [runtime_config: :boolean]
|
||||
{opts, remaining_args} = OptionParser.parse_head!(args, switches: switches)
|
||||
|
||||
if function_exported?(Mix, :ensure_application!, 1) do
|
||||
Mix.ensure_application!(:inets)
|
||||
Mix.ensure_application!(:ssl)
|
||||
end
|
||||
|
||||
if opts[:runtime_config] do
|
||||
Mix.Task.run("app.config")
|
||||
else
|
||||
Application.ensure_all_started(:tree_sitter)
|
||||
end
|
||||
|
||||
Mix.Task.reenable("tree_sitter")
|
||||
install_and_run(remaining_args)
|
||||
end
|
||||
|
||||
defp install_and_run(args) do
|
||||
case TreeSitter.install_and_run(args) do
|
||||
0 -> :ok
|
||||
status -> Mix.raise("`mix tree_sitter #{Enum.join(args, " ")}` exited with #{status}")
|
||||
end
|
||||
end
|
||||
end
|
63
lib/mix/tasks/tree_sitter.install.ex
Normal file
63
lib/mix/tasks/tree_sitter.install.ex
Normal file
|
@ -0,0 +1,63 @@
|
|||
defmodule Mix.Tasks.TreeSitter.Install do
|
||||
@moduledoc """
|
||||
Installs tree_sitter under `_build`.
|
||||
|
||||
```bash
|
||||
$ mix tree_sitter.install
|
||||
$ mix tree_sitter.install --if-missing
|
||||
```
|
||||
|
||||
By default, it installs #{TreeSitter.latest_version()} but you
|
||||
can configure it in your config files, such as:
|
||||
|
||||
config :tree_sitter, :version, "#{TreeSitter.latest_version()}"
|
||||
|
||||
## Options
|
||||
|
||||
* `--runtime-config` - load the runtime configuration
|
||||
before executing command
|
||||
|
||||
* `--if-missing` - install only if the given version
|
||||
does not exist
|
||||
"""
|
||||
|
||||
@shortdoc "Installs tree_sitter under _build"
|
||||
@compile {:no_warn_undefined, Mix}
|
||||
|
||||
use Mix.Task
|
||||
|
||||
@impl true
|
||||
def run(args) do
|
||||
valid_options = [runtime_config: :boolean, if_missing: :boolean]
|
||||
|
||||
case OptionParser.parse_head!(args, strict: valid_options) do
|
||||
{opts, []} ->
|
||||
if opts[:runtime_config], do: Mix.Task.run("app.config")
|
||||
|
||||
if opts[:if_missing] && latest_version?() do
|
||||
:ok
|
||||
else
|
||||
if function_exported?(Mix, :ensure_application!, 1) do
|
||||
Mix.ensure_application!(:inets)
|
||||
Mix.ensure_application!(:ssl)
|
||||
end
|
||||
|
||||
TreeSitter.install()
|
||||
end
|
||||
|
||||
{_, _} ->
|
||||
Mix.raise("""
|
||||
Invalid arguments to tree_sitter.install, expected one of:
|
||||
|
||||
mix tree_sitter.install
|
||||
mix tree_sitter.install --runtime-config
|
||||
mix tree_sitter.install --if-missing
|
||||
""")
|
||||
end
|
||||
end
|
||||
|
||||
defp latest_version?() do
|
||||
version = TreeSitter.configured_version()
|
||||
match?({:ok, ^version}, TreeSitter.bin_version())
|
||||
end
|
||||
end
|
336
lib/tree_sitter.ex
Normal file
336
lib/tree_sitter.ex
Normal file
|
@ -0,0 +1,336 @@
|
|||
defmodule TreeSitter do
|
||||
# https://registry.npmjs.org/tree-sitter/latest
|
||||
@latest_version "0.20.8"
|
||||
|
||||
@moduledoc """
|
||||
TreeSitter is an installer and runner for [tree_sitter](https://tree-sitter.github.io/tree-sitter/).
|
||||
|
||||
## TreeSitter configuration
|
||||
|
||||
There are two global configurations for the tree_sitter application:
|
||||
|
||||
* `:version` - the expected tree_sitter version
|
||||
|
||||
* `:cacerts_path` - the directory to find certificates for
|
||||
https connections
|
||||
|
||||
* `:path` - the path to find the tree_sitter executable at. By
|
||||
default, it is automatically downloaded and placed inside
|
||||
the `_build` directory of your current app
|
||||
|
||||
Overriding the `:path` is not recommended, as we will automatically
|
||||
download and manage `tree-sitter` for you. But in case you can't download
|
||||
it (for example, the npm registry is behind a proxy), you may want to
|
||||
set the `:path` to a configurable system location.
|
||||
|
||||
For instance, you can install `tree-sitter` globally with `npm`:
|
||||
|
||||
$ npm install -g tree-sitter
|
||||
|
||||
On Unix, the executable will be at:
|
||||
|
||||
NPM_ROOT/tree-sitter/node_modules/@tree-sitter/TARGET/bin/tree_sitter
|
||||
|
||||
On Windows, it will be at:
|
||||
|
||||
NPM_ROOT/tree-sitter/node_modules/@tree-sitter/win32-x(32|64)/tree_sitter.exe
|
||||
|
||||
Where `NPM_ROOT` is the result of `npm root -g` and `TARGET` is your system
|
||||
target architecture.
|
||||
|
||||
Once you find the location of the executable, you can store it in a
|
||||
`MIX_TREE_SITTER_PATH` environment variable, which you can then read in
|
||||
your configuration file:
|
||||
|
||||
config :tree_sitter, path: System.get_env("MIX_TREE_SITTER_PATH")
|
||||
|
||||
"""
|
||||
|
||||
use Application
|
||||
require Logger
|
||||
|
||||
@doc false
|
||||
def start(_, _) do
|
||||
unless Application.get_env(:tree_sitter, :version) do
|
||||
Logger.warning("""
|
||||
tree_sitter version is not configured. Please set it in your config files:
|
||||
|
||||
config :tree_sitter, :version, "#{latest_version()}"
|
||||
""")
|
||||
end
|
||||
|
||||
configured_version = configured_version()
|
||||
|
||||
case bin_version() do
|
||||
{:ok, version} ->
|
||||
if version =~ configured_version do
|
||||
:ok
|
||||
else
|
||||
Logger.warning("""
|
||||
Outdated tree_sitter version. Expected #{configured_version}, got #{version}. \
|
||||
Please run `mix tree_sitter.install` or update the version in your config files.\
|
||||
""")
|
||||
end
|
||||
|
||||
:error ->
|
||||
:ok
|
||||
end
|
||||
|
||||
Supervisor.start_link([], strategy: :one_for_one, name: __MODULE__.Supervisor)
|
||||
end
|
||||
|
||||
@doc false
|
||||
# Latest known version at the time of publishing.
|
||||
def latest_version, do: @latest_version
|
||||
|
||||
@doc """
|
||||
Returns the configured tree_sitter version.
|
||||
"""
|
||||
def configured_version do
|
||||
Application.get_env(:tree_sitter, :version, latest_version())
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the path to the executable.
|
||||
|
||||
The executable may not be available if it was not yet installed.
|
||||
"""
|
||||
def bin_path do
|
||||
name = "tree_sitter-#{target()}"
|
||||
|
||||
Application.get_env(:tree_sitter, :path) ||
|
||||
if Code.ensure_loaded?(Mix.Project) do
|
||||
Path.join(Path.dirname(Mix.Project.build_path()), name)
|
||||
else
|
||||
Path.expand("_build/#{name}")
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the version of the tree_sitter executable.
|
||||
|
||||
Returns `{:ok, version_string}` on success or `:error` when the executable
|
||||
is not available.
|
||||
"""
|
||||
def bin_version do
|
||||
path = bin_path()
|
||||
|
||||
with true <- File.exists?(path),
|
||||
{result, 0} <- System.cmd(path, ["--version"]) do
|
||||
{:ok, String.trim(result)}
|
||||
else
|
||||
_ -> :error
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Runs the given command with `args`.
|
||||
|
||||
The given args will be appended to the configured args.
|
||||
The task output will be streamed directly to stdio. It
|
||||
returns the status of the underlying call.
|
||||
"""
|
||||
def run(extra_args) when is_list(extra_args) do
|
||||
opts = [
|
||||
into: IO.stream(:stdio, :line),
|
||||
stderr_to_stdout: true
|
||||
]
|
||||
|
||||
bin_path()
|
||||
|> System.cmd(extra_args, opts)
|
||||
|> elem(1)
|
||||
end
|
||||
|
||||
defp start_unique_install_worker() do
|
||||
ref =
|
||||
__MODULE__.Supervisor
|
||||
|> Supervisor.start_child(
|
||||
Supervisor.child_spec({Task, &install/0}, restart: :transient, id: __MODULE__.Installer)
|
||||
)
|
||||
|> case do
|
||||
{:ok, pid} -> pid
|
||||
{:error, {:already_started, pid}} -> pid
|
||||
end
|
||||
|> Process.monitor()
|
||||
|
||||
receive do
|
||||
{:DOWN, ^ref, _, _, _} -> :ok
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Installs, if not available, and then runs `tree_sitter`.
|
||||
|
||||
Returns the same as `run/1`.
|
||||
"""
|
||||
def install_and_run(args) do
|
||||
File.exists?(bin_path()) || start_unique_install_worker()
|
||||
|
||||
run(args)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Installs tree_sitter with `configured_version/0`.
|
||||
"""
|
||||
def install do
|
||||
version = configured_version()
|
||||
tmp_opts = if System.get_env("MIX_XDG"), do: %{os: :linux}, else: %{}
|
||||
|
||||
tmp_dir =
|
||||
freshdir_p(:filename.basedir(:user_cache, "tree_sitter", tmp_opts)) ||
|
||||
freshdir_p(Path.join(System.tmp_dir!(), "tree_sitter")) ||
|
||||
raise "could not install tree-sitter. Set MIX_XGD=1 and then set XDG_CACHE_HOME to the path you want to use as cache"
|
||||
|
||||
target = target()
|
||||
|
||||
url =
|
||||
"https://github.com/tree-sitter/tree-sitter/releases/download/v#{version}/tree-sitter-#{target}.gz"
|
||||
|
||||
gz = fetch_body!(url)
|
||||
|
||||
result_path =
|
||||
case :os.type() do
|
||||
{:win32, _} ->
|
||||
Path.join([tmp_dir, "tree_sitter.exe"])
|
||||
|
||||
_ ->
|
||||
Path.join([tmp_dir, "tree_sitter"])
|
||||
end
|
||||
|
||||
gz
|
||||
|> :zlib.gunzip()
|
||||
|> then(fn data ->
|
||||
File.write!(result_path, data)
|
||||
end)
|
||||
|
||||
File.chmod!(result_path, 0o700)
|
||||
|
||||
bin_path = bin_path()
|
||||
File.mkdir_p!(Path.dirname(bin_path))
|
||||
|
||||
File.cp!(result_path, bin_path)
|
||||
end
|
||||
|
||||
defp freshdir_p(path) do
|
||||
with {:ok, _} <- File.rm_rf(path),
|
||||
:ok <- File.mkdir_p(path) do
|
||||
path
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
# Available targets: https://github.com/evanw/tree_sitter/tree/main/npm/@tree_sitter
|
||||
defp target do
|
||||
case :os.type() do
|
||||
# Assuming it's an x86 CPU
|
||||
{:win32, _} ->
|
||||
wordsize = :erlang.system_info(:wordsize)
|
||||
|
||||
if wordsize == 8 do
|
||||
"windows-x64"
|
||||
else
|
||||
"windows-x86"
|
||||
end
|
||||
|
||||
{:unix, osname} ->
|
||||
arch_str = :erlang.system_info(:system_architecture)
|
||||
[arch | _] = arch_str |> List.to_string() |> String.split("-")
|
||||
|
||||
osname =
|
||||
if osname == :darwin do
|
||||
"macos"
|
||||
else
|
||||
"linux"
|
||||
end
|
||||
|
||||
case arch do
|
||||
"amd64" -> "#{osname}-arm64"
|
||||
"x86_64" -> "#{osname}-x64"
|
||||
"i686" -> "#{osname}-x86"
|
||||
"i386" -> "#{osname}-x86"
|
||||
"aarch64" -> "#{osname}-arm64"
|
||||
"arm" when osname == "macos" -> "darwin-arm64"
|
||||
"arm" -> "#{osname}-arm"
|
||||
"armv7" <> _ -> "#{osname}-arm"
|
||||
_ -> raise "tree_sitter is not available for architecture: #{arch_str}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch_body!(url) do
|
||||
scheme = URI.parse(url).scheme
|
||||
url = String.to_charlist(url)
|
||||
Logger.debug("Downloading tree_sitter from #{url}")
|
||||
|
||||
{:ok, _} = Application.ensure_all_started(:inets)
|
||||
{:ok, _} = Application.ensure_all_started(:ssl)
|
||||
|
||||
if proxy = proxy_for_scheme(scheme) do
|
||||
%{host: host, port: port} = URI.parse(proxy)
|
||||
Logger.debug("Using #{String.upcase(scheme)}_PROXY: #{proxy}")
|
||||
set_option = if "https" == scheme, do: :https_proxy, else: :proxy
|
||||
:httpc.set_options([{set_option, {{String.to_charlist(host), port}, []}}])
|
||||
end
|
||||
|
||||
# https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets
|
||||
cacertfile = cacertfile() |> String.to_charlist()
|
||||
|
||||
http_options =
|
||||
[
|
||||
ssl: [
|
||||
verify: :verify_peer,
|
||||
cacertfile: cacertfile,
|
||||
depth: 2,
|
||||
customize_hostname_check: [
|
||||
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
|
||||
]
|
||||
]
|
||||
]
|
||||
|> maybe_add_proxy_auth(scheme)
|
||||
|
||||
options = [body_format: :binary]
|
||||
|
||||
case :httpc.request(:get, {url, []}, http_options, options) do
|
||||
{:ok, {{_, 200, _}, _headers, body}} ->
|
||||
body
|
||||
|
||||
other ->
|
||||
raise """
|
||||
couldn't fetch #{url}: #{inspect(other)}
|
||||
|
||||
You may also install the "tree_sitter" executable manually, \
|
||||
see the docs: https://hexdocs.pm/tree_sitter
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
defp proxy_for_scheme("http") do
|
||||
System.get_env("HTTP_PROXY") || System.get_env("http_proxy")
|
||||
end
|
||||
|
||||
defp proxy_for_scheme("https") do
|
||||
System.get_env("HTTPS_PROXY") || System.get_env("https_proxy")
|
||||
end
|
||||
|
||||
defp maybe_add_proxy_auth(http_options, scheme) do
|
||||
case proxy_auth(scheme) do
|
||||
nil -> http_options
|
||||
auth -> [{:proxy_auth, auth} | http_options]
|
||||
end
|
||||
end
|
||||
|
||||
defp proxy_auth(scheme) do
|
||||
with proxy when is_binary(proxy) <- proxy_for_scheme(scheme),
|
||||
%{userinfo: userinfo} when is_binary(userinfo) <- URI.parse(proxy),
|
||||
[username, password] <- String.split(userinfo, ":") do
|
||||
{String.to_charlist(username), String.to_charlist(password)}
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp cacertfile() do
|
||||
Application.get_env(:tree_sitter, :cacerts_path) || CAStore.file_path()
|
||||
end
|
||||
end
|
44
mix.exs
Normal file
44
mix.exs
Normal file
|
@ -0,0 +1,44 @@
|
|||
defmodule TreeSitter.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@version "0.0.1"
|
||||
@source_url "https://gitlab.com/mythic-insight/tree_sitter"
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :tree_sitter,
|
||||
version: @version,
|
||||
elixir: "~> 1.11",
|
||||
deps: deps(),
|
||||
description: "Mix tasks for installing and invoking tree_sitter",
|
||||
package: [
|
||||
links: %{
|
||||
"GitHub" => @source_url,
|
||||
"tree_sitter" => "https://tree-sitter.github.io/tree-sitter/"
|
||||
},
|
||||
licenses: ["MIT"]
|
||||
],
|
||||
docs: [
|
||||
main: "TreeSitter",
|
||||
source_url: @source_url,
|
||||
source_ref: "v#{@version}"
|
||||
],
|
||||
aliases: [test: ["tree_sitter.install --if-missing", "test"]]
|
||||
]
|
||||
end
|
||||
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger, inets: :optional, ssl: :optional],
|
||||
mod: {TreeSitter, []},
|
||||
env: [default: []]
|
||||
]
|
||||
end
|
||||
|
||||
defp deps do
|
||||
[
|
||||
{:castore, ">= 0.0.0"},
|
||||
{:ex_doc, ">= 0.0.0", only: :docs}
|
||||
]
|
||||
end
|
||||
end
|
9
mix.lock
Normal file
9
mix.lock
Normal file
|
@ -0,0 +1,9 @@
|
|||
%{
|
||||
"castore": {:hex, :castore, "0.1.11", "c0665858e0e1c3e8c27178e73dffea699a5b28eb72239a3b2642d208e8594914", [:mix], [], "hexpm", "91b009ba61973b532b84f7c09ce441cba7aa15cb8b006cf06c6f4bba18220081"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"},
|
||||
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"},
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
|
||||
}
|
1
test/test_helper.exs
Normal file
1
test/test_helper.exs
Normal file
|
@ -0,0 +1 @@
|
|||
ExUnit.start()
|
31
test/tree_sitter_test.exs
Normal file
31
test/tree_sitter_test.exs
Normal file
|
@ -0,0 +1,31 @@
|
|||
defmodule TreeSitterTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
@version TreeSitter.latest_version()
|
||||
|
||||
test "runs" do
|
||||
assert ExUnit.CaptureIO.capture_io(fn ->
|
||||
assert TreeSitter.run(["--version"]) == 0
|
||||
end) =~ @version
|
||||
end
|
||||
|
||||
test "updates on install" do
|
||||
Application.put_env(:tree_sitter, :version, "0.20.6")
|
||||
|
||||
Mix.Task.rerun("tree_sitter.install", ["--if-missing"])
|
||||
|
||||
assert ExUnit.CaptureIO.capture_io(fn ->
|
||||
assert TreeSitter.run(["--version"]) == 0
|
||||
end) =~ "0.20.6"
|
||||
|
||||
Application.delete_env(:tree_sitter, :version)
|
||||
|
||||
Mix.Task.rerun("tree_sitter.install", ["--if-missing"])
|
||||
|
||||
assert ExUnit.CaptureIO.capture_io(fn ->
|
||||
assert TreeSitter.run(["--version"]) == 0
|
||||
end) =~ @version
|
||||
after
|
||||
Application.delete_env(:tree_sitter, :version)
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue