Skip to content

Commit

Permalink
chore: work on build
Browse files Browse the repository at this point in the history
  • Loading branch information
zachdaniel committed Aug 14, 2022
1 parent 18396a1 commit 5ae9cee
Show file tree
Hide file tree
Showing 19 changed files with 4,071 additions and 15 deletions.
Empty file added .check.exs
Empty file.
202 changes: 202 additions & 0 deletions .credo.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# This file contains the configuration for Credo and you are probably reading
# this after creating it with `mix credo.gen.config`.
#
# If you find anything wrong or unclear in this file, please report an
# issue on GitHub: https://github.com/rrrene/credo/issues
#
%{
#
# You can have as many configs as you like in the `configs:` field.
configs: [
%{
#
# Run any config using `mix credo -C <name>`. If no config name is given
# "default" is used.
#
name: "default",
#
# These are the files included in the analysis:
files: %{
#
# You can give explicit globs or simply directories.
# In the latter case `**/*.{ex,exs}` will be used.
#
included: [
"lib/",
"src/",
"test/",
"web/",
"apps/*/lib/",
"apps/*/src/",
"apps/*/test/",
"apps/*/web/"
],
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
},
#
# Load and configure plugins here:
#
plugins: [],
#
# If you create your own checks, you must specify the source files for
# them here, so they can be loaded by Credo before running the analysis.
#
requires: [],
#
# If you want to enforce a style guide and need a more traditional linting
# experience, you can change `strict` to `true` below:
#
strict: false,
#
# To modify the timeout for parsing files, change this value:
#
parse_timeout: 5000,
#
# If you want to use uncolored output by default, you can change `color`
# to `false` below:
#
color: true,
#
# You can customize the parameters of any check by adding a second element
# to the tuple.
#
# To disable a check put `false` as second element:
#
# {Credo.Check.Design.DuplicatedCode, false}
#
checks: %{
enabled: [
#
## Consistency Checks
#
{Credo.Check.Consistency.ExceptionNames, []},
{Credo.Check.Consistency.LineEndings, []},
{Credo.Check.Consistency.ParameterPatternMatching, []},
{Credo.Check.Consistency.SpaceAroundOperators, []},
{Credo.Check.Consistency.SpaceInParentheses, []},
{Credo.Check.Consistency.TabsOrSpaces, []},

#
## Design Checks
#
{Credo.Check.Design.AliasUsage, false},
{Credo.Check.Design.TagTODO, [exit_status: 2]},
{Credo.Check.Design.TagFIXME, []},

#
## Readability Checks
#
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
{Credo.Check.Readability.ParenthesesInCondition, []},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
{Credo.Check.Readability.PipeIntoAnonymousFunctions, []},
{Credo.Check.Readability.PredicateFunctionNames, []},
{Credo.Check.Readability.PreferImplicitTry, []},
{Credo.Check.Readability.RedundantBlankLines, []},
{Credo.Check.Readability.Semicolons, []},
{Credo.Check.Readability.SpaceAfterCommas, []},
{Credo.Check.Readability.StringSigils, []},
{Credo.Check.Readability.TrailingBlankLine, []},
{Credo.Check.Readability.TrailingWhiteSpace, []},
{Credo.Check.Readability.UnnecessaryAliasExpansion, []},
{Credo.Check.Readability.VariableNames, []},
{Credo.Check.Readability.WithSingleClause, []},

#
## Refactoring Opportunities
#
{Credo.Check.Refactor.Apply, false},
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, false},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, false},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.MapJoin, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, [max_nesting: 5]},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.WithClauses, []},
{Credo.Check.Refactor.FilterFilter, []},
{Credo.Check.Refactor.RejectReject, []},
{Credo.Check.Refactor.RedundantWithClauseResult, []},

#
## Warnings
#
{Credo.Check.Warning.ApplicationConfigInModuleAttribute, []},
{Credo.Check.Warning.BoolOperationOnSameValues, []},
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
{Credo.Check.Warning.SpecWithStruct, []},
{Credo.Check.Warning.WrongTestFileExtension, []},
{Credo.Check.Warning.UnusedEnumOperation, []},
{Credo.Check.Warning.UnusedFileOperation, []},
{Credo.Check.Warning.UnusedKeywordOperation, []},
{Credo.Check.Warning.UnusedListOperation, []},
{Credo.Check.Warning.UnusedPathOperation, []},
{Credo.Check.Warning.UnusedRegexOperation, []},
{Credo.Check.Warning.UnusedStringOperation, []},
{Credo.Check.Warning.UnusedTupleOperation, []},
{Credo.Check.Warning.UnsafeExec, []}
],
disabled: [
#
# Checks scheduled for next check update (opt-in for now, just replace `false` with `[]`)

#
# Controversial and experimental checks (opt-in, just move the check to `:enabled`
# and be sure to use `mix credo --strict` to see low priority checks)
#
{Credo.Check.Consistency.MultiAliasImportRequireUse, []},
{Credo.Check.Consistency.UnusedVariableNames, []},
{Credo.Check.Design.DuplicatedCode, []},
{Credo.Check.Design.SkipTestWithoutComment, []},
{Credo.Check.Readability.AliasAs, []},
{Credo.Check.Readability.BlockPipe, []},
{Credo.Check.Readability.ImplTrue, []},
{Credo.Check.Readability.MultiAlias, []},
{Credo.Check.Readability.NestedFunctionCalls, []},
{Credo.Check.Readability.SeparateAliasRequire, []},
{Credo.Check.Readability.SingleFunctionToBlockPipe, []},
{Credo.Check.Readability.SinglePipe, []},
{Credo.Check.Readability.Specs, []},
{Credo.Check.Readability.StrictModuleLayout, []},
{Credo.Check.Readability.WithCustomTaggedTuple, []},
{Credo.Check.Refactor.ABCSize, []},
{Credo.Check.Refactor.AppendSingleItem, []},
{Credo.Check.Refactor.DoubleBooleanNegation, []},
{Credo.Check.Refactor.FilterReject, []},
{Credo.Check.Refactor.IoPuts, []},
{Credo.Check.Refactor.MapMap, []},
{Credo.Check.Refactor.ModuleDependencies, []},
{Credo.Check.Refactor.NegatedIsNil, []},
{Credo.Check.Refactor.PipeChainStart, []},
{Credo.Check.Refactor.RejectFilter, []},
{Credo.Check.Refactor.VariableRebinding, []},
{Credo.Check.Warning.LazyLogging, []},
{Credo.Check.Warning.LeakyEnvironment, []},
{Credo.Check.Warning.MapGetUnsafePass, []},
{Credo.Check.Warning.MixEnv, []},
{Credo.Check.Warning.UnsafeToAtom, []}

# {Credo.Check.Refactor.MapInto, []},

#
# Custom checks can be created using `mix credo.gen.check`.
#
]
}
}
]
}
23 changes: 12 additions & 11 deletions lib/spark.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ defmodule Spark do
Documentation for `Spark`.
"""

@doc """
Hello world.
## Examples
iex> Spark.hello()
:world
"""
def hello do
:world
@doc "Returns true if the module implements the specified behavior"
def implements_behaviour?(module, behaviour) do
:attributes
|> module.module_info()
|> Enum.flat_map(fn
{:behaviour, value} -> List.wrap(value)
_ -> []
end)
|> Enum.any?(&(&1 == behaviour))
rescue
_ ->
false
end
end
135 changes: 135 additions & 0 deletions lib/spark/doc_index.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
defmodule Spark.DocIndex do
@moduledoc """
A module for creating an index of documentation for a library. Can be rendered by tools like `ash_hq`.
There is a small template syntax available in any documentation.
The template syntax will link to the user's currently selected
version for the relevant library.
All templates should be wrapped in double curly braces, e.g `{{}}`.
## Links to other documentation
`{{link:library:item_type:name}}`
For example:
`{{link:ash:guide:Attributes}}` might be transformed to `<a href="/docs/guides/ash/topics/attributes.md">Attributes</a>`
## Mix dependencies
`{{mix_dep:library}}`
For example:
`{{mix_dep:ash}}` might be transformed to `{:ash, "~> 1.5"}`
"""

@type extension :: %{
optional(:module) => module,
optional(:target) => String.t(),
optional(:default_for_target?) => boolean,
:name => String.t(),
:type => String.t()
}

@type guide :: %{
name: String.t(),
text: String.t(),
category: String.t() | nil,
route: String.t() | nil
}

@callback extensions() :: list(extension())
@callback for_library() :: String.t()
@callback guides() :: list(guide())
@callback code_modules() :: [{String.t(), list(module())}]
@callback default_guide() :: String.t()

defmacro __using__(opts) do
quote bind_quoted: [otp_app: opts[:otp_app], guides_from: opts[:guides_from]] do
@behaviour Spark.DocIndex

if guides_from do
@impl Spark.DocIndex
# sobelow_skip ["Traversal.FileModule"]
def guides do
unquote(otp_app)
|> :code.priv_dir()
|> Path.join(unquote(guides_from))
|> Path.wildcard()
|> Enum.map(fn path ->
path
|> Path.split()
|> Enum.reverse()
|> Enum.take(2)
|> Enum.reverse()
|> case do
[category, file] ->
%{
name: Spark.DocIndex.to_name(Path.rootname(file)),
category: Spark.DocIndex.to_name(category),
text: File.read!(path),
route: "#{Spark.DocIndex.to_path(category)}/#{Spark.DocIndex.to_path(file)}"
}
end
end)
end

defoverridable guides: 0
end
end
end

def find_undocumented_items(doc_index) do
Enum.each(doc_index.extensions(), fn extension ->
Enum.each(
extension.module.sections(),
&find_undocumented_in_section(&1, [inspect(extension.module)])
)
end)
end

defp find_undocumented_in_section(section, path) do
find_undocumented_in_schema(section.schema(), [section.name() | path])
Enum.each(section.sections(), &find_undocumented_in_section(&1, [section.name() | path]))
Enum.each(section.entities(), &find_undocumented_in_entity(&1, [section.name() | path]))
end

defp find_undocumented_in_entity(entity, path) do
find_undocumented_in_schema(entity.schema(), [entity.name() | path])

Enum.each(entity.entities(), fn {_key, entities} ->
Enum.each(entities, &find_undocumented_in_entity(&1, [entity.name() | path]))
end)
end

defp find_undocumented_in_schema(schema, path) do
Enum.each(schema, fn {key, opts} ->
if !opts[:links] do
raise "Undocumented item #{Enum.reverse(path) |> Enum.join(".")}.#{key}"
end
end)
end

# sobelow_skip ["Traversal.FileModule"]
def read!(app, path) do
app
|> :code.priv_dir()
|> Path.join(path)
|> File.read!()
end

def to_name(string) do
string
|> String.split(~r/[-_]/, trim: true)
|> Enum.map_join(" ", &String.capitalize/1)
end

def to_path(string) do
string
|> String.split(~r/\s/, trim: true)
|> Enum.join("-")
|> String.downcase()
end
end
Loading

0 comments on commit 5ae9cee

Please sign in to comment.