Skip to content

Commit

Permalink
Add typespecs and fix some Credo warnings (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
rustra committed Jun 21, 2020
1 parent bee796b commit 40b44ed
Show file tree
Hide file tree
Showing 14 changed files with 714 additions and 694 deletions.
187 changes: 97 additions & 90 deletions lib/json/ld/compaction.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,35 @@ defmodule JSON.LD.Compaction do
@moduledoc nil

import JSON.LD.Utils
alias JSON.LD.Context

def compact(input, context, options \\ %JSON.LD.Options{}) do
with options = JSON.LD.Options.new(options),
active_context = JSON.LD.context(context, options),
inverse_context = Context.inverse(active_context),
expanded = JSON.LD.expand(input, options) do
result =
case do_compact(expanded, active_context, inverse_context, nil, options.compact_arrays) do
[] ->
%{}

result when is_list(result) ->
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
%{compact_iri("@graph", active_context, inverse_context, nil, true) => result}

result ->
result
end

if Context.empty?(active_context),
do: result,
else: Map.put(result, "@context", context["@context"] || context)
end
alias JSON.LD.{Context, Options}

@spec compact(map | [map], map | nil, Options.t() | Enum.t()) :: map
def compact(input, context, options \\ %Options{}) do
options = Options.new(options)
active_context = JSON.LD.context(context, options)
inverse_context = Context.inverse(active_context)
expanded = JSON.LD.expand(input, options)

result =
case do_compact(expanded, active_context, inverse_context, nil, options.compact_arrays) do
[] ->
%{}

result when is_list(result) ->
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
%{compact_iri("@graph", active_context, inverse_context, nil, true) => result}

result ->
result
end

if Context.empty?(active_context),
do: result,
else: Map.put(result, "@context", context["@context"] || context)
end

@spec do_compact(any, Context.t(), map, String.t() | nil, boolean) :: any
defp do_compact(
element,
active_context,
Expand Down Expand Up @@ -92,6 +95,7 @@ defmodule JSON.LD.Compaction do
end
end

@spec do_compact_non_scalar(any, Context.t(), map, String.t() | nil, boolean) :: any
defp do_compact_non_scalar(
element,
active_context,
Expand Down Expand Up @@ -133,13 +137,10 @@ defmodule JSON.LD.Compaction do
[compact_iri(expanded_type, active_context, inverse_context, nil, true)]
end)
# 7.1.2.3)
|> case(
do:
(
[compacted_value] -> compacted_value
compacted_value -> compacted_value
)
)
|> case do
[compacted_value] -> compacted_value
compacted_value -> compacted_value
end
end

# 7.1.3)
Expand All @@ -162,8 +163,7 @@ defmodule JSON.LD.Compaction do
if term_def && term_def.reverse_property do
# 7.2.2.1.1)
value =
if (!compact_arrays or term_def.container_mapping == "@set") and
!is_list(value) do
if (!compact_arrays or term_def.container_mapping == "@set") and !is_list(value) do
[value]
else
value
Expand Down Expand Up @@ -324,6 +324,7 @@ defmodule JSON.LD.Compaction do
end)
end

@spec merge_compacted_value(map, String.t(), any) :: map
defp merge_compacted_value(map, key, value) do
Map.update(map, key, value, fn
old_value when is_list(old_value) and is_list(value) ->
Expand All @@ -345,6 +346,7 @@ defmodule JSON.LD.Compaction do
Details at <https://www.w3.org/TR/json-ld-api/#iri-compaction>
"""
@spec compact_iri(any, Context.t(), map, any | nil, boolean, boolean) :: any | nil
def compact_iri(
iri,
active_context,
Expand Down Expand Up @@ -398,68 +400,70 @@ defmodule JSON.LD.Compaction do
else
# 2.6.4) For each item in list:
{common_type, common_language} =
Enum.reduce_while(list, {common_type, common_language}, fn item,
{common_type,
common_language} ->
# 2.6.4.1) Initialize item language to @none and item type to @none.
{item_type, item_language} = {"@none", "@none"}
# 2.6.4.2) If item contains the key @value:
{item_type, item_language} =
if Map.has_key?(item, "@value") do
Enum.reduce_while(
list,
{common_type, common_language},
fn item, {common_type, common_language} ->
# 2.6.4.1) Initialize item language to @none and item type to @none.
{item_type, item_language} = {"@none", "@none"}
# 2.6.4.2) If item contains the key @value:
{item_type, item_language} =
if Map.has_key?(item, "@value") do
cond do
# 2.6.4.2.1) If item contains the key @language, then set item language to its associated value.
Map.has_key?(item, "@language") ->
{item_type, item["@language"]}

# 2.6.4.2.2) Otherwise, if item contains the key @type, set item type to its associated value.
Map.has_key?(item, "@type") ->
{item["@type"], item_language}

# 2.6.4.2.3) Otherwise, set item language to @null.
true ->
{item_type, "@null"}
end

# 2.6.4.3) Otherwise, set item type to @id.
else
{"@id", item_language}
end

common_language =
cond do
# 2.6.4.2.1) If item contains the key @language, then set item language to its associated value.
Map.has_key?(item, "@language") ->
{item_type, item["@language"]}
# 2.6.4.4) If common language is null, set it to item language.
is_nil(common_language) ->
item_language

# 2.6.4.2.2) Otherwise, if item contains the key @type, set item type to its associated value.
Map.has_key?(item, "@type") ->
{item["@type"], item_language}
# 2.6.4.5) Otherwise, if item language does not equal common language and item contains the key @value, then set common language to @none because list items have conflicting languages.
item_language != common_language and Map.has_key?(item, "@value") ->
"@none"

# 2.6.4.2.3) Otherwise, set item language to @null.
true ->
{item_type, "@null"}
common_language
end

# 2.6.4.3) Otherwise, set item type to @id.
else
{"@id", item_language}
end

common_language =
cond do
# 2.6.4.4) If common language is null, set it to item language.
is_nil(common_language) ->
item_language

# 2.6.4.5) Otherwise, if item language does not equal common language and item contains the key @value, then set common language to @none because list items have conflicting languages.
item_language != common_language and Map.has_key?(item, "@value") ->
"@none"

true ->
common_language
end
common_type =
cond do
# 2.6.4.6) If common type is null, set it to item type.
is_nil(common_type) ->
item_type

common_type =
cond do
# 2.6.4.6) If common type is null, set it to item type.
is_nil(common_type) ->
item_type
# 2.6.4.7) Otherwise, if item type does not equal common type, then set common type to @none because list items have conflicting types.
item_type != common_type ->
"@none"

# 2.6.4.7) Otherwise, if item type does not equal common type, then set common type to @none because list items have conflicting types.
item_type != common_type ->
"@none"
true ->
common_type
end

true ->
common_type
# 2.6.4.8) If common language is @none and common type is @none, then stop processing items in the list because it has been detected that there is no common language or type amongst the items.
if common_language == "@none" and common_type == "@none" do
{:halt, {common_type, common_language}}
else
{:cont, {common_type, common_language}}
end

# 2.6.4.8) If common language is @none and common type is @none, then stop processing items in the list because it has been detected that there is no common language or type amongst the items.
if common_language == "@none" and common_type == "@none" do
{:halt, {common_type, common_language}}
else
{:cont, {common_type, common_language}}
end
end)
)

# 2.6.5) If common language is null, set it to @none.
common_language = if is_nil(common_language), do: "@none", else: common_language
Expand Down Expand Up @@ -535,9 +539,9 @@ defmodule JSON.LD.Compaction do
# 2.12.1) If the result of using the IRI compaction algorithm, passing active context, inverse context, the value associated with the @id key in value for iri, true for vocab, and true for document relative has a term definition in the active context with an IRI mapping that equals the value associated with the @id key in value, then append @vocab, @id, and @none, in that order, to preferred values.
# TODO: Spec fixme? document_relative is not a specified parameter of compact_iri
compact_id = compact_iri(value["@id"], active_context, inverse_context, nil, true)
term_def = active_context.term_defs[compact_id]

if (term_def = active_context.term_defs[compact_id]) &&
term_def.iri_mapping == value["@id"] do
if term_def && term_def.iri_mapping == value["@id"] do
preferred_values ++ ~w[@vocab @id @none]

# 2.12.2) Otherwise, append @id, @vocab, and @none, in that order, to preferred values.
Expand Down Expand Up @@ -624,11 +628,13 @@ defmodule JSON.LD.Compaction do
end
end

@spec shortest_or_least?(String.t(), String.t()) :: boolean
defp shortest_or_least?(a, b) do
(a_len = String.length(a)) < (b_len = String.length(b)) or
(a_len == b_len and a < b)
end

@spec remove_base(String.t(), String.t() | nil) :: String.t()
defp remove_base(iri, nil), do: iri

defp remove_base(iri, base) do
Expand All @@ -638,15 +644,13 @@ defmodule JSON.LD.Compaction do
String.split_at(iri, base_len) |> elem(1)
else
case URI.parse(base) do
%URI{path: nil} ->
iri

base ->
do_remove_base(iri, %URI{base | path: parent_path(base.path)}, 0)
%URI{path: nil} -> iri
base -> do_remove_base(iri, %URI{base | path: parent_path(base.path)}, 0)
end
end
end

@spec do_remove_base(String.t(), URI.t(), non_neg_integer) :: String.t()
defp do_remove_base(iri, base, index) do
base_str = URI.to_string(base)

Expand All @@ -666,6 +670,7 @@ defmodule JSON.LD.Compaction do
end
end

@spec parent_path(String.t()) :: String.t()
defp parent_path("/"), do: "/"

defp parent_path(path) do
Expand All @@ -680,6 +685,7 @@ defmodule JSON.LD.Compaction do
Details at <https://www.w3.org/TR/json-ld-api/#value-compaction>
"""
@spec compact_value(any, Context.t(), map, String.t()) :: any
def compact_value(value, active_context, inverse_context, active_property) do
term_def = active_context.term_defs[active_property]
# 1) Initialize number members to the number of members value contains.
Expand Down Expand Up @@ -750,6 +756,7 @@ defmodule JSON.LD.Compaction do
Details at <https://www.w3.org/TR/json-ld-api/#term-selection>
"""
@spec select_term(map, String.t(), [String.t()], String.t(), [String.t()]) :: String.t()
def select_term(inverse_context, iri, containers, type_language, preferred_values) do
container_map = inverse_context[iri]

Expand Down
Loading

0 comments on commit 40b44ed

Please sign in to comment.