Skip to content

Update Name serialization to use JSON string #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"tasks": {
"build": "npm install && npm run build",
"test": "elm-test"
}
}
13 changes: 10 additions & 3 deletions src/Morphir/IR/FQName.elm
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
-}


module Morphir.IR.FQName exposing (FQName, fQName, fromQName, getPackagePath, getModulePath, getLocalName, fqn, toString, fromString, fromStringStrict)
module Morphir.IR.FQName exposing (FQName, fQName, fromQName, getPackagePath, getModulePath, getLocalName, fqn, toString, fromString, fromStringStrict, empty)

{-| Module to work with fully-qualified names. A qualified name is a combination of a package path, a module path and a local name.

@docs FQName, fQName, fromQName, getPackagePath, getModulePath, getLocalName, fqn, toString, fromString, fromStringStrict
@docs FQName, fQName, fromQName, getPackagePath, getModulePath, getLocalName, fqn, toString, fromString, fromStringStrict, empty

-}

Expand Down Expand Up @@ -103,7 +103,7 @@ fromString fqNameString splitter =
)

_ ->
( [ [] ], [], [] )
empty


{-| Parse a string into a FQName using splitter as the separator between package, module and local names. Fail if it's
Expand Down Expand Up @@ -132,3 +132,10 @@ fromStringStrict fqNameString separator =
, "' as the separator."
]
)


{-| Create an empty fully-qualified name.
-}
empty : FQName
empty =
( [], [], "" )
136 changes: 36 additions & 100 deletions src/Morphir/IR/Name.elm
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ module Morphir.IR.Name exposing
allows us to use the same identifiers across various naming conventions used by the different
frontend and backend languages Morphir integrates with.

name = fromList [ "value", "in", "u", "s", "d" ]
name = fromString "valueInUSD"

toTitleCase name --> "ValueInUSD"
toCamelCase name --> "valueInUSD"
toSnakeCase name --> "value_in_USD"
toSnakeCase name --> "value_in_usd"


## Abbreviations
Expand Down Expand Up @@ -62,96 +62,77 @@ import Regex exposing (Regex)
{-| Type that represents a name that is made up of words.
-}
type alias Name =
List String
String


{-| Translate a string into a name by splitting it into words. The algorithm is designed
to work with most well-known naming conventions or mix of them. The general rule is that
consecutive letters and numbers are treated as words, upper-case letters and non-alphanumeric
characters start a new word.
{-| Translate a string into a name by returning the input string directly.

fromString "fooBar_baz 123"
--> Name.fromList [ "foo", "bar", "baz", "123" ]
--> "fooBar_baz 123"

fromString "valueInUSD"
--> Name.fromList [ "value", "in", "u", "s", "d" ]
--> "valueInUSD"

fromString "ValueInUSD"
--> Name.fromList [ "value", "in", "u", "s", "d" ]
--> "ValueInUSD"

fromString "value_in_USD"
--> Name.fromList [ "value", "in", "u", "s", "d" ]
--> "value_in_USD"

fromString "_-%"
--> Name.fromList []
--> "_-%"

-}
fromString : String -> Name
fromString string =
let
wordPattern : Regex
wordPattern =
Regex.fromString "([a-zA-Z][a-z]*|[0-9]+)"
|> Maybe.withDefault Regex.never
in
Regex.find wordPattern string
|> List.map .match
|> List.map String.toLower
|> fromList
string


{-| Turns a name into a title-case string.

toTitleCase (fromList [ "foo", "bar", "baz", "123" ])
--> "FooBarBaz123"
toTitleCase "fooBar_baz 123"
--> "Foobarbaz123"

toTitleCase (fromList [ "value", "in", "u", "s", "d" ])
--> "ValueInUSD"
toTitleCase "valueInUSD"
--> "Valueinusd"

-}
toTitleCase : Name -> String
toTitleCase name =
name
|> toList
|> List.map capitalize
|> String.join ""
|> String.toLower
|> capitalize


{-| Turns a name into a camel-case string.

toCamelCase (fromList [ "foo", "bar", "baz", "123" ])
--> "fooBarBaz123"
toCamelCase "fooBar_baz 123"
--> "foobarbaz123"

toCamelCase (fromList [ "value", "in", "u", "s", "d" ])
--> "valueInUSD"
toCamelCase "valueInUSD"
--> "valueinusd"

-}
toCamelCase : Name -> String
toCamelCase name =
case name |> toList of
[] ->
""

head :: tail ->
tail
|> List.map capitalize
|> (::) head
|> String.join ""
name
|> String.toLower


{-| Turns a name into a snake-case string.

toSnakeCase (fromList [ "foo", "bar", "baz", "123" ])
toSnakeCase "fooBar_baz 123"
--> "foo_bar_baz_123"

toSnakeCase (fromList [ "value", "in", "u", "s", "d" ])
--> "value_in_USD"
toSnakeCase "valueInUSD"
--> "value_in_usd"

-}
toSnakeCase : Name -> String
toSnakeCase name =
name
|> toHumanWords
|> String.toLower
|> String.split " "
|> String.join "_"


Expand All @@ -160,72 +141,27 @@ compared to [`toList`](#toList) is how it handles abbreviations. They will
be turned into a single upper-case word instead of separate single-character
words.

toHumanWords (fromList [ "value", "in", "u", "s", "d" ])
--> [ "value", "in", "USD" ]
toHumanWords "valueInUSD"
--> [ "valueinusd" ]

-}
toHumanWords : Name -> List String
toHumanWords name =
let
words : List String
words =
toList name

join : List String -> String
join abbrev =
abbrev
|> String.join ""
|> String.toUpper

process : List String -> List String -> List String -> List String
process prefix abbrev suffix =
case suffix of
[] ->
if List.isEmpty abbrev then
prefix

else
List.append prefix [ join abbrev ]

first :: rest ->
if String.length first == 1 then
process prefix (List.append abbrev [ first ]) rest

else
case abbrev of
[] ->
process (List.append prefix [ first ]) [] rest

_ ->
process (List.append prefix [ join abbrev, first ]) [] rest
in
case name of
[word] ->
if String.length word == 1 then
name
else
process [] [] words
_ ->
process [] [] words
[ name |> String.toLower ]


{-| Turns a name into a list of human-readable strings with the first word capitalized. The only difference
compared to [`toList`](#toList) is how it handles abbreviations. They will
be turned into a single upper-case word instead of separate single-character
words.

toHumanWordsTitle (fromList [ "value", "in", "u", "s", "d" ])
--> [ "Value", "in", "USD" ]
toHumanWordsTitle "valueInUSD"
--> [ "Valueinusd" ]

-}
toHumanWordsTitle : Name -> List String
toHumanWordsTitle name =
case toHumanWords name of
firstWord :: rest ->
capitalize firstWord :: rest

[] ->
[]
[ name |> String.toLower |> capitalize ]


capitalize : String -> String
Expand All @@ -242,11 +178,11 @@ capitalize string =
-}
fromList : List String -> Name
fromList words =
words
String.join "" words


{-| Convert a name to a list of strings.
-}
toList : Name -> List String
toList words =
words
toList name =
[ name ]
6 changes: 2 additions & 4 deletions src/Morphir/IR/Name/Codec.elm
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ import Morphir.IR.Name as Name exposing (Name)
encodeName : Name -> Encode.Value
encodeName name =
name
|> Name.toList
|> Encode.list Encode.string
|> Encode.string


{-| Decode a name from JSON.
-}
decodeName : Decode.Decoder Name
decodeName =
Decode.list Decode.string
|> Decode.map Name.fromList
Decode.string
6 changes: 2 additions & 4 deletions src/Morphir/IR/Name/CodecV1.elm
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ import Morphir.IR.Name as Name exposing (Name)
encodeName : Name -> Encode.Value
encodeName name =
name
|> Name.toList
|> Encode.list Encode.string
|> Encode.string


{-| Decode a name from JSON.
-}
decodeName : Decode.Decoder Name
decodeName =
Decode.list Decode.string
|> Decode.map Name.fromList
Decode.string
6 changes: 3 additions & 3 deletions src/Morphir/JsonSchema/Backend.elm
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ mapType qName typ =
tupleSchemaList
|> ResultList.keepAllErrors
|> Result.mapError List.concat
|> Result.map (\tupleSchema -> Array (ListType (Array (TupleType tupleSchema) False)) True)
|> Result.map (\tupleSchema -> Array (TupleType tupleSchema) True)

_ ->
Ok
Expand Down Expand Up @@ -415,7 +415,7 @@ generateSchemaByTypeNameOrModuleName inputString pkgName pkgDef =
Just moduleDefi ->
let
typeDefinitionsFound =
getTypeDefinitionsFromModule typeName modulePath (Just moduleDefi) pkgName pkgDef
getTypeDefinitionsFromModule (Name.fromString (List.head typeName |> Maybe.withDefault "")) modulePath (Just moduleDefi) pkgName pkgDef
in
if (typeDefinitionsFound |> List.length) > 0 then
typeDefinitionsFound
Expand All @@ -435,7 +435,7 @@ generateSchemaByTypeNameOrModuleName inputString pkgName pkgDef =
)

else
Err [ "Type " ++ (typeName |> Name.toTitleCase) ++ " not found in the module: " ++ Path.toString Name.toTitleCase "." modulePath ]
Err [ "Type " ++ (typeName |> List.head |> Maybe.withDefault "" |> Name.toTitleCase) ++ " not found in the module: " ++ Path.toString Name.toTitleCase "." modulePath ]

Nothing ->
Err [ "Module found in the package: " ++ inputString ]
1 change: 1 addition & 0 deletions src/Morphir/JsonSchema/Backend/Codec.elm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Morphir.JsonSchema.Backend.Codec exposing (..)

import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
import Morphir.IR.Name.Codec exposing (decodeName, encodeName)
import Morphir.IR.Path as Path
import Morphir.JsonSchema.Backend exposing (Errors, Options)
import Set
Expand Down
Loading
Loading