Composer.Recipe.Locator (composer v0.2.0)

Copy Markdown View Source

Finds where things are written in a recipe group file, without evaluating it.

index/2 parses a group's source and records, for each recipe in the final keyword list:

  • key - the range of its name key (auth:)
  • keys - its own keys (steps:, aliases:, flags:, ...)
  • refs - the reference strings in its steps:, in source order, including the string of a {"ref", opts} entry
  • uses - the strings of its {:use, ...} entries
  • entries - each entry's range and, when it is literal, its value
  • aliases - each alias name, from a literal aliases: or from the top-level binding that aliases: names
  • alias_targets - each alias's target, where it is a literal string
  • ifs - each if: flag atom

Top-level name = ... bindings are recorded too, and a steps: or aliases: that names one is read through it.

Positions follow Composer.Lint.Diagnostic: 1-based lines, columns counted in characters as Elixir's tokenizer counts them, and ranges {{line, column}, {end_line, end_column}} with an exclusive end. The index keeps each line's text (line/2), so a caller needing another column unit (an LSP's UTF-16) can convert without parsing again.

locate/3 answers "where is this?" and always returns a range, falling back from the literal to the recipe's steps: key, to its name key, to line 1. at/3 answers "what is here?".

Summary

Functions

Returns what is at line, column: a reference, a {:use, ...} target, an alias name, a recipe key or a recipe's name key, as {kind, recipe_name, value, range}, or nil.

The range used when nothing better is known: the start of line 1.

Indexes a group file's source; path is recorded and words errors. Returns {:error, {:group_parse, path, description, line}} when the source does not parse.

Reads and indexes the group file at path.

Returns line n's text (without its newline), or nil.

Returns the most precise range for target in recipe name. When target cannot be found, falls back to the recipe's steps: key (or, for an alias, its aliases:), then its name key, then line 1.

The parse options the locator uses, for parsing other files alike.

Returns the indexed recipe named name (the first, if duplicated).

Returns the ranges of every name key name, in file order.

Returns the ranges of the reference strings (in steps: and {:use, ...}) of recipe name that equal match, or satisfy it when it is a function, in source order.

Types

range()

@type range() :: Composer.Lint.Diagnostic.range()

recipe()

@type recipe() :: %{
  name: String.t(),
  key: range(),
  keys: %{required(atom()) => range()},
  refs: [{String.t(), range()}],
  uses: [{String.t(), range()}],
  entries: [{range(), term()}],
  aliases: %{required(atom()) => range()},
  alias_targets: %{required(atom()) => String.t()},
  ifs: %{required(atom()) => range()}
}

t()

@type t() :: %Composer.Recipe.Locator{
  bindings: %{required(atom()) => range()},
  lines: tuple(),
  path: Path.t(),
  recipes: [recipe()]
}

target()

@type target() ::
  :recipe
  | {:ref, String.t() | (String.t() -> boolean())}
  | {:use, String.t()}
  | {:entry, term()}
  | {:key, atom()}
  | {:if, atom()}
  | {:alias, atom()}

Functions

at(locator, line, column)

@spec at(t(), pos_integer(), pos_integer()) ::
  {:ref | :use | :alias | :key | :recipe, String.t(), term(), range()} | nil

Returns what is at line, column: a reference, a {:use, ...} target, an alias name, a recipe key or a recipe's name key, as {kind, recipe_name, value, range}, or nil.

first_line()

@spec first_line() :: range()

The range used when nothing better is known: the start of line 1.

index(source, path)

@spec index(String.t(), Path.t()) :: {:ok, t()} | {:error, term()}

Indexes a group file's source; path is recorded and words errors. Returns {:error, {:group_parse, path, description, line}} when the source does not parse.

index_file(path)

@spec index_file(Path.t()) :: {:ok, t()} | {:error, term()}

Reads and indexes the group file at path.

line(locator, n)

@spec line(t(), pos_integer()) :: String.t() | nil

Returns line n's text (without its newline), or nil.

locate(index, name, target)

@spec locate(t(), String.t(), target()) :: range()

Returns the most precise range for target in recipe name. When target cannot be found, falls back to the recipe's steps: key (or, for an alias, its aliases:), then its name key, then line 1.

parse_opts()

@spec parse_opts() :: keyword()

The parse options the locator uses, for parsing other files alike.

recipe(locator, name)

@spec recipe(t(), String.t()) :: recipe() | nil

Returns the indexed recipe named name (the first, if duplicated).

recipe_keys(locator, name)

@spec recipe_keys(t(), String.t()) :: [range()]

Returns the ranges of every name key name, in file order.

refs(index, name, match)

@spec refs(t(), String.t(), String.t() | (String.t() -> boolean())) :: [range()]

Returns the ranges of the reference strings (in steps: and {:use, ...}) of recipe name that equal match, or satisfy it when it is a function, in source order.