diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 48248fd2d..359af09a4 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -13,16 +13,16 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node-version: [16.x] + node-version: [18.x] os: [ ubuntu-latest ] steps: - - uses: actions/checkout@v2 - + - uses: actions/checkout@v4 + - name: Setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - + - name: Cache NPM uses: actions/cache@v3 with: @@ -30,34 +30,34 @@ jobs: key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - + - name: Cache Elm uses: actions/cache@v3 with: path: ~/.elm key: ${{ runner.os }}-elm-${{ hashFiles('**/elm.json') }} restore-keys: | - ${{ runner.os }}-elm- - + ${{ runner.os }}-elm- + - name: Download dependencies run: npm ci - + - name: Build run: npm run build --if-present - + - name: Running Test run: npm test - # CVE scanning + # CVE scanning cvescan: name: CVE Scanning runs-on: ubuntu-latest needs: [ build ] strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -76,7 +76,7 @@ jobs: # Skip any PR created by dependabot to avoid permission issues if: (github.actor != 'dependabot[bot]') steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: semgrep scan --config auto --severity ERROR env: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} diff --git a/.gitignore b/.gitignore index 271f4c618..398f984f3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,9 +13,13 @@ redistributable/Scala cli/web/insightapp.js cli/treeStuff.js cli/index.html +cli2/lib/ lib/geneated cadl-Frontend/cadl-output Morphir.Elm.CLI.js +Morphir.Elm.Generator.js docs.json /.coverage/ -tests-integration/reference-model/Dockerfile \ No newline at end of file +tests-integration/reference-model/Dockerfile + +.scala-build/ \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..a77793ecc --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/hydrogen diff --git a/README.md b/README.md index 99df460b9..e38f95647 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ structure follows the structure of the IR. Here's a list of concepts in a top-do ## Contributing -[Contribution Guide](docs/contribution-guide.md) +[Contribution Guide](CONTRIBUTING.md) 1. Fork it () 2. Create your feature branch (`git checkout -b feature/fooBar`) @@ -206,7 +206,7 @@ _NOTE:_ Commits and pull requests to FINOS repositories will only be accepted fr ### Publishing new releases -[Steps for publishing a new release](docs/publishing.md) +[Steps for publishing a new release](publishing.md) ## License diff --git a/cli/cli.js b/cli/cli.js index 31703c7dd..7ba6ab044 100644 --- a/cli/cli.js +++ b/cli/cli.js @@ -84,8 +84,14 @@ async function gen(input, outputPath, options) { opts.limitToModules = options.modulesToInclude ? options.modulesToInclude.split(",") : null opts.includeCodecs = options.includeCodecs ? true : false opts.filename = options.filename == '' ? '' : options.filename - const fileMap = await generate(opts, JSON.parse(morphirIrJson.toString())) + if (options.decorations) { + if (await fileExist(path.resolve(options.decorations))) { + options.decorationsObj = JSON.parse(await readFile(path.resolve(options.decorations))) + } + } + + const fileMap = await generate(opts, JSON.parse(morphirIrJson.toString())) const writePromises = fileMap.map(async ([ [dirPath, fileName], content @@ -134,7 +140,9 @@ function copyRedistributables(options, outputPath) { copyScalaFeature('core') } else if (options.target == 'TypeScript') { copyFiles('TypeScript/', outputPath) - } + } else if (options.target == 'Snowpark') { + copyFiles('Snowpark/', outputPath) + } } function copyRecursiveSync(src, dest) { diff --git a/cli/elm.json b/cli/elm.json index 8ab79cae4..477410e75 100644 --- a/cli/elm.json +++ b/cli/elm.json @@ -20,6 +20,7 @@ "elm/regex": "1.0.0", "elm/svg": "1.0.1", "elm/url": "1.0.0", + "elm/time": "1.0.0", "elm-community/array-extra": "2.6.0", "elm-community/graph": "6.0.0", "elm-community/list-extra": "8.7.0", @@ -30,6 +31,7 @@ "lattyware/elm-fontawesome": "6.0.0", "matthewsj/elm-ordering": "2.0.0", "mdgriffith/elm-ui": "1.1.8", + "perzanko/elm-loading": "2.0.5", "pzp1997/assoc-list": "1.0.0", "rundis/elm-bootstrap": "5.2.0", "stil4m/elm-syntax": "7.2.9" @@ -39,11 +41,12 @@ "avh4/elm-fifo": "1.0.4", "elm/bytes": "1.0.8", "elm/file": "1.0.5", - "elm/time": "1.0.0", "elm/virtual-dom": "1.0.3", "elm-community/intdict": "3.0.0", "miniBill/elm-unicode": "1.0.3", "myrho/elm-round": "1.0.5", + "robinheghan/murmur3": "1.0.0", + "rtfeldman/elm-css": "17.1.1", "rtfeldman/elm-hex": "1.0.0", "stil4m/structured-writer": "1.0.3" } diff --git a/cli/morphir-elm-develop.js b/cli/morphir-elm-develop.js index e17bd675f..aa8f55030 100644 --- a/cli/morphir-elm-develop.js +++ b/cli/morphir-elm-develop.js @@ -36,7 +36,7 @@ const webDir = path.join(__dirname, "web"); app.use(express.static(webDir, { index: false })); -app.use(express.json()); +app.use(express.json({limit: "100mb"})); app.get("/", wrap(async (req, res, next) => { res.setHeader('Content-type', 'text/html') @@ -102,6 +102,21 @@ app.post( }) ); +app.post( + "/server/morphir-ir.json", + wrap(async (req, res, next) => { + const morphirIRJsonPath = path.join( + program.opts().projectDir, + "morphir-ir.json" + ); + var jsonContent = JSON.stringify(req.body, null, 4); + await writeFile(morphirIRJsonPath, jsonContent); + const morphirIRJsonContent = await readFile(morphirIRJsonPath); + const morphirIRJson = JSON.parse(morphirIRJsonContent.toString()); + res.send(morphirIRJson); + }) +); + app.get("*", wrap(async (req, res, next) => { res.setHeader('Content-type', 'text/html') res.send(await indexHtmlWithVersion()); diff --git a/cli/morphir-elm-gen.js b/cli/morphir-elm-gen.js index 45433c374..946307456 100644 --- a/cli/morphir-elm-gen.js +++ b/cli/morphir-elm-gen.js @@ -23,6 +23,7 @@ program .option('-s, --include-codecs', 'Generate JSON codecs', false) .option('-f, --filename ', 'Filename of the generated JSON Schema.', '') .option('-ls, --include ', 'Limit what will be included.', '') + .option('-dec, --decorations ', 'JSON file with decorations') .parse(process.argv) cli.gen(program.opts().input, path.resolve(program.opts().output), program.opts()) diff --git a/cli/morphir-elm-make.js b/cli/morphir-elm-make.js index a1bcc47e5..45359e2fd 100644 --- a/cli/morphir-elm-make.js +++ b/cli/morphir-elm-make.js @@ -18,6 +18,7 @@ program .option('-o, --output ', 'Target file location where the Morphir IR will be saved.', 'morphir-ir.json') .option('-t, --types-only', 'Only include type information in the IR, no values.', false) .option('-f, --fallback-cli', 'Use old cli make function.', false) + .option('-i, --indent-json', 'Use indentation in the generated JSON file.', false) .parse(process.argv) const programOptions = program.opts() @@ -43,7 +44,7 @@ function make(projectDir, opts) { cli.make(projectDir, opts) .then((packageDef) => { console.log(`Writing file ${opts.output}.`) - cli.writeFile(opts.output, JSON.stringify(packageDef, null, 4)) + cli.writeFile(opts.output, JSON.stringify(packageDef, null, opts.indentJson ? 4 : 0)) .then(() => { console.log('Done.') }) diff --git a/cli/src/Morphir/Elm/CLI.elm b/cli/src/Morphir/Elm/CLI.elm index 69288d818..eedd004db 100644 --- a/cli/src/Morphir/Elm/CLI.elm +++ b/cli/src/Morphir/Elm/CLI.elm @@ -189,8 +189,14 @@ update msg model = let resultIR : Result Decode.Error Distribution resultIR = - distributionJson - |> Decode.decodeValue DistributionCodec.decodeVersionedDistribution + case distributionJson |> Decode.decodeValue DistributionCodec.decodeVersionedDistribution of + Ok packageDist -> + case packageDist of + Library packageName dependencies packageDef -> + Ok (Library packageName (Dict.union Frontend.defaultDependencies dependencies) packageDef) + + Err err -> + Err err in case resultIR of Ok ir -> diff --git a/cli/src/Morphir/Elm/Target.elm b/cli/src/Morphir/Elm/Target.elm index 02695fb96..19ba2c92d 100644 --- a/cli/src/Morphir/Elm/Target.elm +++ b/cli/src/Morphir/Elm/Target.elm @@ -19,6 +19,7 @@ import Morphir.SpringBoot.Backend.Codec import Morphir.TypeScript.Backend import Morphir.TypeSpec.Backend import Morphir.TypeSpec.Backend.Codec +import Morphir.Snowpark.Backend @@ -34,6 +35,7 @@ type BackendOptions | SparkOptions Morphir.Scala.Spark.Backend.Options | JsonSchemaOptions Morphir.JsonSchema.Backend.Options | TypeSpecOptions Morphir.TypeSpec.Backend.Options + | SnowparkOptions Morphir.Snowpark.Backend.Options decodeOptions : Result Error String -> Decode.Decoder BackendOptions @@ -53,6 +55,9 @@ decodeOptions gen = Ok "Spark" -> Decode.map SparkOptions (Decode.succeed Morphir.Scala.Spark.Backend.Options) + + Ok "Snowpark" -> + Decode.map SnowparkOptions Morphir.Snowpark.Backend.decodeOptions Ok "JsonSchema" -> Decode.map JsonSchemaOptions Morphir.JsonSchema.Backend.Codec.decodeOptions @@ -85,6 +90,9 @@ mapDistribution back dist = SparkOptions options -> Ok <| Morphir.Spark.Backend.mapDistribution options dist + + SnowparkOptions options -> + Ok <| Morphir.Snowpark.Backend.mapDistribution options dist JsonSchemaOptions options -> Morphir.JsonSchema.Backend.mapDistribution options dist diff --git a/cli/src/Morphir/Web/DevelopApp.elm b/cli/src/Morphir/Web/DevelopApp.elm index 52e1fc86b..d4f935ad9 100644 --- a/cli/src/Morphir/Web/DevelopApp.elm +++ b/cli/src/Morphir/Web/DevelopApp.elm @@ -1,4 +1,4 @@ -module Morphir.Web.DevelopApp exposing (IRState(..), Model, Msg(..), ServerState(..), httpMakeModel, init, main, routeParser, subscriptions, update, view, viewBody, viewHeader) +port module Morphir.Web.DevelopApp exposing (IRState(..), Model, Msg(..), ServerState(..), httpMakeModel, init, main, routeParser, subscriptions, update, view, viewBody, viewHeader) import Array exposing (Array) import Array.Extra @@ -22,6 +22,7 @@ import Element , fillPortion , height , image + , inFront , layout , link , maximum @@ -51,13 +52,14 @@ import Element.Keyed import FontAwesome.Styles as Icon import Http exposing (emptyBody, jsonBody) import List.Extra +import Loading import Morphir.Correctness.Codec exposing (decodeTestSuite, encodeTestSuite) import Morphir.Correctness.Test exposing (TestCase, TestSuite) import Morphir.IR.Decoration exposing (AllDecorationConfigAndData, DecorationData, DecorationID) import Morphir.IR.Decoration.Codec exposing (decodeAllDecorationConfigAndData, decodeDecorationData, encodeDecorationData) -import Morphir.IR.Distribution exposing (Distribution(..)) +import Morphir.IR.Distribution as Distribution exposing (Distribution(..)) import Morphir.IR.Distribution.Codec as DistributionCodec -import Morphir.IR.FQName exposing (FQName) +import Morphir.IR.FQName as FQName exposing (FQName) import Morphir.IR.Module as Module exposing (ModuleName) import Morphir.IR.Name as Name exposing (Name) import Morphir.IR.NodeId exposing (NodeID(..)) @@ -65,9 +67,10 @@ import Morphir.IR.Package as Package exposing (PackageName) import Morphir.IR.Path as Path exposing (Path) import Morphir.IR.Repo as Repo exposing (Repo) import Morphir.IR.SDK as SDK exposing (packageName) -import Morphir.IR.Type as Type exposing (Type) +import Morphir.IR.Type as Type exposing (Type(..)) import Morphir.IR.Value as Value exposing (RawValue, Value(..)) import Morphir.SDK.Dict as SDKDict +import Morphir.TestCoverage.Backend exposing (getBranchCoverage, getValueBranchCoverage) import Morphir.Type.Infer as Infer import Morphir.Value.Error exposing (Error) import Morphir.Value.Interpreter exposing (complete, evaluateFunctionValue) @@ -80,6 +83,7 @@ import Morphir.Visual.Components.SectionComponent as SectionComponent import Morphir.Visual.Components.SelectableElement as SelectableElement import Morphir.Visual.Components.TabsComponent as TabsComponent import Morphir.Visual.Components.TreeViewComponent as TreeViewComponent +import Morphir.Visual.Components.TypeBuilder as TypeBuilder import Morphir.Visual.Config exposing (DrillDownFunctions(..), ExpressionTreePath, PopupScreenRecord, addToDrillDown, removeFromDrillDown) import Morphir.Visual.EnrichedValue exposing (fromRawValue) import Morphir.Visual.Theme as Theme exposing (Theme, borderBottom, borderRounded, largePadding, largeSpacing, smallPadding) @@ -111,6 +115,9 @@ main = } +port unsavedChangesPort : Bool -> Cmd msg + + -- MODEL @@ -127,6 +134,7 @@ type alias Model = , homeState : HomeState , repo : Repo , insightViewState : Morphir.Visual.Config.VisualState + , typeBuilderState : TypeBuilder.State , argStates : InsightArgumentState , expandedValues : Dict ( FQName, Name ) (Value.Definition () (Type ())) , allDecorationConfigAndData : AllDecorationConfigAndData @@ -139,6 +147,7 @@ type alias Model = , modalContent : Element Msg , version : String , showSaveTestError : Bool + , unsavedChanges : Bool } @@ -182,6 +191,7 @@ type Definition type IRState = IRLoading + | IRReloading Distribution | IRLoaded Distribution @@ -216,6 +226,7 @@ init flags url key = } , repo = Repo.empty [] , insightViewState = emptyVisualState + , typeBuilderState = TypeBuilder.init Nothing False , argStates = Dict.empty , expandedValues = Dict.empty , allDecorationConfigAndData = Dict.empty @@ -228,6 +239,7 @@ init flags url key = , modalContent = none , version = flags.version , showSaveTestError = False + , unsavedChanges = False } in ( toRoute url initModel @@ -307,6 +319,9 @@ type UIMsg | OpenHttpErrorModal Http.Error String Bool | DismissHttpError | CloseModal + | TypeBuilderChanged TypeBuilder.State + | TypeAdded TypeBuilder.NewType + | SaveIR type FilterMsg @@ -400,8 +415,8 @@ update msg model = in case Repo.fromDistribution distribution of Ok r -> - ( { model | irState = irLoaded, repo = r, argStates = initialArgumentStates, insightViewState = initInsightViewState initialArgumentStates } - , httpTestModel distribution + ( { model | irState = irLoaded, repo = r, argStates = initialArgumentStates, insightViewState = initInsightViewState initialArgumentStates, unsavedChanges = False } + , Cmd.batch [ httpTestModel distribution, unsavedChangesPort False ] ) Err _ -> @@ -464,6 +479,22 @@ update msg model = CloseModal -> ( { model | isModalOpen = False }, Cmd.none ) + TypeBuilderChanged newTypeBuilderState -> + ( { model | typeBuilderState = newTypeBuilderState }, Cmd.none ) + + TypeAdded newType -> + case model.repo |> Repo.insertType newType.moduleName newType.name newType.definition newType.access newType.documentation of + Ok newRepo -> + ( { model | typeBuilderState = TypeBuilder.init (model.homeState.selectedModule |> Maybe.map Tuple.second) True, unsavedChanges = True, irState = IRLoaded (Repo.toDistribution newRepo), repo = newRepo } + , unsavedChangesPort True + ) + + _ -> + ( model, Cmd.none ) + + SaveIR -> + ( { model | irState = IRReloading (Repo.toDistribution model.repo) }, httpSaveDistribution (Repo.toDistribution model.repo) ) + ServerGetTestsResponse testSuite -> ( { model | testSuite = fromStoredTestSuite testSuite }, Cmd.none ) @@ -793,10 +824,18 @@ updateHomeState pack mod def filterState = initialArgState = initArgumentStates model.irState maybeSelectedDefinition in - { model | homeState = newState, insightViewState = initInsightViewState initialArgState, argStates = initialArgState, selectedTestcaseIndex = -1, testDescription = "", openSections = Set.fromList [ 1 ] } + { model + | homeState = newState + , insightViewState = initInsightViewState initialArgState + , argStates = initialArgState + , selectedTestcaseIndex = -1 + , testDescription = "" + , openSections = Set.fromList [ 1 ] + , typeBuilderState = TypeBuilder.init (newState.selectedModule |> Maybe.map Tuple.second) model.unsavedChanges + } -- When selecting a definition, we should not change the selected module, once the user explicitly selected one - keepOrChangeSelectedModule : ( List Path, List Name ) + keepOrChangeSelectedModule : ( List Path, ModuleName ) keepOrChangeSelectedModule = if filterState.moduleClicked == pack then ( urlFragmentToNodePath "", [] ) @@ -1070,6 +1109,13 @@ viewHeader model = (text "Morphir Web") ] } + , el + [ alignRight + , Font.color model.theme.colors.lightest + , Font.size (Theme.scaled 5 model.theme) + ] + <| + ifThenElse model.unsavedChanges (text " You have unsaved changes! ") Element.none , el [ alignRight , pointer @@ -1216,6 +1262,19 @@ viewBody model = (text "Loading the IR ...") ) + IRReloading (Library packageName _ packageDef) -> + el + [ width fill + , height fill + , centerX + , centerY + , inFront <| + el [ Background.color model.theme.colors.lightGray, onClick DoNothing, width fill, height fill ] <| + el [ centerX, centerY ] <| + Element.html (Loading.render Loading.Circle Loading.defaultConfig Loading.On) + ] + (viewHome model packageName packageDef) + IRLoaded (Library packageName _ packageDef) -> viewHome model packageName packageDef @@ -1303,7 +1362,7 @@ viewDecorationValues model node = editorState ) ) - |> FieldList.view + |> FieldList.view model.theme in column [ spacing (model.theme |> Theme.scaled 5) ] [ attributeToEditors ] @@ -1415,27 +1474,35 @@ viewHome model packageName packageDef = , activeTab = model.activeTabIndex , tabs = Array.fromList - [ { name = "Summary" - , content = col [ summary ] - } - , { name = "Dependency Graph" - , content = col [ dependencyGraph model.homeState.selectedModule model.repo ] - } - , { name = "Decorations" - , content = - let - decorationTabContent = - case maybeModuleName of - Just moduleName -> - [ viewDecorationValues model (ModuleID ( packageName, moduleName )) ] - - Nothing -> - -- Since we don't annotate package for now, we don't show the Value Editors - [] - in - col decorationTabContent - } - ] + ([ { name = "Summary" + , content = col [ summary ] + } + , { name = "Dependency Graph" + , content = col [ dependencyGraph model.homeState.selectedModule model.repo ] + } + ] + ++ (case maybeModuleName of + Just moduleName -> + [ { name = "Decorations" + , content = + col [ viewDecorationValues model (ModuleID ( packageName, moduleName )) ] + } + , { name = "Add new term" + , content = + col <| + [ TypeBuilder.view model.theme + { state = model.typeBuilderState, onStateChange = UI << TypeBuilderChanged, onTypeAdd = UI << TypeAdded, onIRSave = UI SaveIR } + packageName + packageDef + moduleName + ] + } + ] + + Nothing -> + [] + ) + ) } in row [ width fill, height fill, Background.color model.theme.colors.gray, spacing (Theme.smallSpacing model.theme) ] @@ -1924,6 +1991,25 @@ httpSaveTestSuite ir newTestSuite oldTestSuite = } +httpSaveDistribution : Distribution -> Cmd Msg +httpSaveDistribution distribution = + Http.post + { url = "/server/morphir-ir.json" + , body = jsonBody <| DistributionCodec.encodeVersionedDistribution distribution + , expect = + Http.expectJson + (\response -> + case response of + Err httpError -> + HttpError "We encountered an issue while saving the IR" httpError + + Ok result -> + ServerGetIRResponse result + ) + DistributionCodec.decodeVersionedDistribution + } + + {-| Display a Tree View of clickable module names in the given package, with urls pointing to the give module -} viewModuleNames : Model -> PackageName -> ModuleName -> List ModuleName -> TreeViewComponent.Node ModuleName Msg @@ -2040,7 +2126,7 @@ viewDefinitionDetails model = (argState |> Dict.get argName |> Maybe.withDefault (ValueEditor.initEditorState ir argType Nothing)) ) ) - |> FieldList.view + |> FieldList.view model.theme buttonStyles : List (Element.Attribute msg) buttonStyles = @@ -2143,6 +2229,38 @@ viewDefinitionDetails model = Err error -> el [ centerX, centerY ] (text (Infer.typeErrorToMessage error)) + testCoverageMetrics : Distribution -> FQName -> Element Msg + testCoverageMetrics distro fqName = + let + testCases = + model.testSuite + |> Dict.get fqName + |> Maybe.map Array.toList + |> Maybe.withDefault [] + + maybeValueDef = + Distribution.lookupValueDefinition fqName distro + in + maybeValueDef + |> Maybe.map (\valueDef -> getValueBranchCoverage valueDef testCases distro) + |> Maybe.map + (\{ numberOfBranches, numberOfCoveredBranches } -> + row + [ Border.width 1 + , Border.color model.theme.colors.darkest + , Border.roundEach { topLeft = 5, bottomLeft = 5, topRight = 5, bottomRight = 5 } + , padding (model.theme |> Theme.scaled 3) + ] + [ column [] + [ row [ Font.bold, Font.size 22, paddingXY 0 10 ] [ text "Test Coverage Percentage - ", text <| String.fromInt (Basics.floor ((toFloat numberOfCoveredBranches / toFloat numberOfBranches) * 100)) ++ "%" ] + , row [ Font.bold, Font.size 15, paddingXY 0 10 ] [ text "Break down" ] + , row [ Font.bold, Font.size 15, paddingXY 0 10 ] [ text "Number of branches - ", text <| String.fromInt numberOfBranches ] + , row [ Font.bold, Font.size 15, paddingXY 0 10 ] [ text "Number of covered branches - ", text <| String.fromInt numberOfCoveredBranches ] + ] + ] + ) + |> Maybe.withDefault (text "") + scenarios : FQName -> Distribution -> List ( Name, a, Type () ) -> Element Msg scenarios fQName ir inputTypes = let @@ -2338,7 +2456,11 @@ viewDefinitionDetails model = { title = "Test Cases" , onToggle = UI (ToggleSection 3) , isOpen = Set.member 3 model.openSections - , content = scenarios fullyQualifiedName distribution valueDef.inputTypes + , content = + column [ spacing (model.theme |> Theme.scaled 4) ] + [ testCoverageMetrics distribution fullyQualifiedName + , scenarios fullyQualifiedName distribution valueDef.inputTypes + ] } ] } @@ -2413,7 +2535,7 @@ viewDefinitionDetails model = Nothing -> none - IRLoading -> + _ -> none @@ -2455,7 +2577,7 @@ initArgumentStates irState maybeSelectedDefinition = Nothing -> Dict.empty - IRLoading -> + _ -> Dict.empty diff --git a/cli/src/Morphir/Web/Editor.elm b/cli/src/Morphir/Web/Editor.elm index 53e8c54c4..8ecd098af 100644 --- a/cli/src/Morphir/Web/Editor.elm +++ b/cli/src/Morphir/Web/Editor.elm @@ -5,7 +5,6 @@ import Element import Html exposing (Html) import Json.Decode as Decode exposing (Decoder) import Json.Encode as Encode -import Morphir.IR as IR exposing (IR) import Morphir.IR.Distribution exposing (Distribution) import Morphir.IR.Distribution.Codec exposing (decodeVersionedDistribution) import Morphir.IR.FQName as FQName exposing (FQName) @@ -25,7 +24,7 @@ type alias Model = type alias ModelState = - { ir : IR + { ir : Distribution , theme : Theme , valueType : Type () , editorState : ValueEditor.EditorState @@ -60,24 +59,24 @@ init flags = tpe = Type.Reference () flag.entryPoint [] - ir : IR - ir = - IR.fromDistribution flag.distribution + distro : Distribution + distro = + flag.distribution initEditorState : ValueEditor.EditorState initEditorState = - ValueEditor.initEditorState ir tpe flag.initialValue + ValueEditor.initEditorState distro tpe flag.initialValue encoderResult : Result String (RawValue -> Result String Encode.Value) encoderResult = - DataCodec.encodeData ir tpe + DataCodec.encodeData distro tpe model : Model model = encoderResult |> Result.map (\encoder -> - { ir = ir + { ir = distro , theme = Theme.fromConfig Nothing , valueType = tpe , editorState = initEditorState @@ -200,7 +199,7 @@ decodeFlag = in Decode.field "initialValue" (Decode.maybe - (decodeData (IR.fromDistribution distribution) tpe + (decodeData distribution tpe |> decodeResultToFailure ) ) diff --git a/cli/src/Morphir/Web/InsightTestApp.elm b/cli/src/Morphir/Web/InsightTestApp.elm index 5b48dd922..20cb29be0 100644 --- a/cli/src/Morphir/Web/InsightTestApp.elm +++ b/cli/src/Morphir/Web/InsightTestApp.elm @@ -11,8 +11,7 @@ import Html exposing (Html) import Http import Morphir.Correctness.Codec exposing (decodeTestSuite) import Morphir.Correctness.Test exposing (TestCases, TestSuite) -import Morphir.IR as IR exposing (IR) -import Morphir.IR.Distribution exposing (Distribution(..)) +import Morphir.IR.Distribution as Distribution exposing (Distribution(..)) import Morphir.IR.Distribution.Codec as DistributionCodec import Morphir.IR.FQName exposing (FQName) import Morphir.IR.Name as Name exposing (Name) @@ -39,8 +38,8 @@ type alias Flags = type Model = LoadingDistribution - | LoadingTests Distribution IR - | Initialized Distribution IR TestSuite + | LoadingTests Distribution + | Initialized Distribution TestSuite | Errored String @@ -76,7 +75,7 @@ httpGetDistribution = } -httpGetTestModel : IR -> Cmd Msg +httpGetTestModel : Distribution -> Cmd Msg httpGetTestModel ir = Http.get { url = "/server/morphir-tests.json" @@ -103,19 +102,15 @@ update msg model = _ -> case ( model, msg ) of ( LoadingDistribution, HttpGetDistributionResponse distro ) -> - let - ir = - IR.fromDistribution distro - in - ( LoadingTests distro ir, httpGetTestModel ir ) + ( LoadingTests distro, httpGetTestModel distro ) ( LoadingDistribution, HttpError error ) -> ( Errored "Error while loading distribution", Cmd.none ) - ( LoadingTests distro ir, HttpGetTestsResponse testSuite ) -> - ( Initialized distro ir testSuite, Cmd.none ) + ( LoadingTests distro, HttpGetTestsResponse testSuite ) -> + ( Initialized distro testSuite, Cmd.none ) - ( LoadingTests distro ir, HttpError error ) -> + ( LoadingTests distro, HttpError error ) -> ( Errored "Error while loading tests", Cmd.none ) _ -> @@ -146,35 +141,34 @@ viewModel model = LoadingDistribution -> text "Loading distribution ..." - LoadingTests _ _ -> + LoadingTests _ -> text "Loading tests ..." - Initialized distro ir testSuite -> - viewInitialized distro ir testSuite + Initialized distro testSuite -> + viewInitialized distro testSuite Errored string -> text string -viewInitialized : Distribution -> IR -> TestSuite -> Element Msg -viewInitialized distro ir testSuite = +viewInitialized : Distribution -> TestSuite -> Element Msg +viewInitialized distro testSuite = testSuite |> Dict.toList |> List.filterMap (\( fqn, testCases ) -> - ir - |> IR.lookupValueDefinition fqn + distro + |> Distribution.lookupValueDefinition fqn |> Maybe.map (\valueDef -> - viewValue ir fqn valueDef testCases + viewValue distro fqn valueDef testCases ) ) |> column [ spacing 10 ] - -viewValue : IR -> FQName -> Value.Definition () (Type ()) -> TestCases -> Element Msg -viewValue ir (( _, moduleName, localName ) as fqn) valueDefinition testCases = +viewValue : Distribution -> FQName -> Value.Definition () (Type ()) -> TestCases -> Element Msg +viewValue distro (( _, moduleName, localName ) as fqn) valueDefinition testCases = let cardColor : Element.Color cardColor = @@ -205,7 +199,7 @@ viewValue ir (( _, moduleName, localName ) as fqn) valueDefinition testCases = , padding 10 , Background.color (rgb 1 1 1) ] - (viewInsight ir + (viewInsight distro fqn valueDefinition inputs @@ -245,8 +239,8 @@ viewValue ir (( _, moduleName, localName ) as fqn) valueDefinition testCases = viewCases -viewInsight : IR -> FQName -> Value.Definition () (Type ()) -> List (Maybe RawValue) -> Element Msg -viewInsight ir fqn valueDef argValues = +viewInsight : Distribution -> FQName -> Value.Definition () (Type ()) -> List (Maybe RawValue) -> Element Msg +viewInsight distro fqn valueDef argValues = let variables : Dict Name RawValue variables = @@ -261,7 +255,7 @@ viewInsight ir fqn valueDef argValues = |> Dict.fromList config = - { ir = ir + { ir = distro , nativeFunctions = SDK.nativeFunctions , state = { drillDownFunctions = DrillDownFunctions Dict.empty diff --git a/cli/src/Morphir/Web/TryMorphir.elm b/cli/src/Morphir/Web/TryMorphir.elm index 7ee7ee482..93ab3b344 100644 --- a/cli/src/Morphir/Web/TryMorphir.elm +++ b/cli/src/Morphir/Web/TryMorphir.elm @@ -427,7 +427,7 @@ viewValue valueState ir fullyQualifiedName irView valueDef = (ValueEditor.initEditorState ir argType Nothing) ) ) - |> FieldList.view + |> FieldList.view theme in column [] [ editors diff --git a/cli/web/index.html b/cli/web/index.html index 48685e9c3..59a9dcdf0 100644 --- a/cli/web/index.html +++ b/cli/web/index.html @@ -24,6 +24,18 @@ node: document.getElementById("elm"), flags: {version : "__VERSION_NUMBER__"} }); + var unsaved = false; + + app.ports.unsavedChangesPort.subscribe(message => { + unsaved = message; + }); + + window.addEventListener("beforeunload", event => { + if (unsaved) { + event.returnValue = "unsaved changes"; + return event.returnValue; + } + }); } catch (e) { // display initialization errors (e.g. bad flags, infinite recursion) var header = document.createElement("h1"); diff --git a/cli2/.gitignore b/cli2/.gitignore index 251f9f790..ee89266bb 100644 --- a/cli2/.gitignore +++ b/cli2/.gitignore @@ -1,5 +1,4 @@ node_modules morphir-elm.ts package-lock.json -package.json -lib \ No newline at end of file +package.json \ No newline at end of file diff --git a/cli2/cli.ts b/cli2/cli.ts index e711097a2..78533df97 100644 --- a/cli2/cli.ts +++ b/cli2/cli.ts @@ -135,7 +135,7 @@ async function buildFromScratch( if (err) { reject(err); } else { - resolve(JSON.stringify(ok, null, 4)); + resolve(JSON.stringify(ok, null, options.indentJson ? 4 : 0)); } }); @@ -176,7 +176,7 @@ async function buildIncrementally( if (err) { reject(err); } else { - resolve(JSON.stringify(ok, null, 4)); + resolve(JSON.stringify(ok, null, options.indentJson ? 4 : 0)); } }); @@ -519,8 +519,8 @@ async function testCoverage( // output path const output = path.join(path.resolve(outputPath), "morphir-test-coverage.json") - - return new Promise((resolve, reject) => { + + return new Promise((resolve, reject) => { worker.ports.testCoverageResult.subscribe(([err, data]: any) => { if (err) { reject(err) @@ -531,7 +531,7 @@ async function testCoverage( }) // send files through port - worker.ports.testCoverage.send([morphirIRJson,morphirTestJson]) + worker.ports.testCoverage.send([morphirIRJson, morphirTestJson]) }); } diff --git a/cli2/elm.json b/cli2/elm.json index 4b482c56c..aaf2e301c 100644 --- a/cli2/elm.json +++ b/cli2/elm.json @@ -21,6 +21,7 @@ "elm/regex": "1.0.0", "elm/svg": "1.0.1", "elm/url": "1.0.0", + "elm/time": "1.0.0", "elm-community/array-extra": "2.3.0", "elm-community/graph": "6.0.0", "elm-community/list-extra": "8.2.3", @@ -38,7 +39,6 @@ "avh4/elm-fifo": "1.0.4", "elm/bytes": "1.0.8", "elm/file": "1.0.5", - "elm/time": "1.0.0", "elm/virtual-dom": "1.0.2", "elm-community/intdict": "3.0.0", "elm-community/json-extra": "4.2.0", diff --git a/cli2/morphir-init.ts b/cli2/morphir-init.ts new file mode 100644 index 000000000..f121df332 --- /dev/null +++ b/cli2/morphir-init.ts @@ -0,0 +1,150 @@ +import FileSystemModule from 'fs' +import chalk from 'chalk' +import path from 'path' +import { promisify } from 'util' +import { Command } from 'commander' +import inquirer, { Answers, Question } from 'inquirer' + +const exists = promisify(FileSystemModule.exists) +const writeFile = promisify(FileSystemModule.writeFile) +const readFile = promisify(FileSystemModule.readFile) +const mkdir = promisify(FileSystemModule.mkdir) + +interface InitAnswers extends Answers { + name: string + type: string + dir: string +} + +interface CreateDirAnswer extends Answers { + shouldCreate: boolean +} + +const program = new Command() +program + .name('morphir init') + .description('Launches an interactive session to initialize a new morphir project.') + .parse(process.argv) + +console.log(chalk.blue('-- NEW MORPHIR PROJECT ---------------------------------------\n')) + +console.log("I'll create a new morphir project for you, you just need to provide some details.\n") +inquirer + .prompt([ + { + type: 'list', + name: 'type', + message: 'Select project type', + choices: ['Business Model', 'Decoration Schema'], + default: 0 + }, + { + type: 'input', + name: 'name', + message: 'Project Name (no spaces)', + default: 'Demo', + validate(input: string) { + // prevent spaces, leading digits and a leading lowercase. + if (input.includes(' ')) + return `You can't have spaces in there. You could try: ${getSuggestions(input)}` + if (input.match(/^\d/)) return `Project name can't start with a number` + if (input[0] === input[0].toLowerCase()) return `It can't start with a lowercase character` + return true + } + }, + { + type: 'input', + name: 'dir', + message: 'Where do you want to create it? (use `.` for current directory)', + default(answer: { name: string }) { + return `./${answer.name}` + } + } + ]) + .then(async (answers: InitAnswers) => { + const { name, dir } = answers + + console.log() + console.log(chalk.blue(`Creating your new morphir project\n`)) + + const projectPath = path.resolve(dir) + + // check if there's a morphir.json at the directory + if (await exists(path.join(projectPath, 'morphir.json'))) { + console.log(chalk.blue(`The path you specified already contains a morphir project. Exiting.`)) + process.exit(0) + } + + // ask to create a new dir if it doesn't exist + if (!(await exists(projectPath))) { + try { + const { shouldCreate }: CreateDirAnswer = await inquirer.prompt([ + { + type: 'confirm', + message: `The directory you provided doesn't exist. Do you want me to create a new directory at\n"${projectPath}"?`, + name: 'shouldCreate', + default: false + } + ]) + + if (shouldCreate) await mkdir(projectPath) + else { + console.log( + chalk.blue( + 'Cannot create new project because the specified directory does not exists. Exiting.' + ) + ) + process.exit(0) + } + } catch (e: unknown) { + console.log(chalk.red(`Failed to create directory: ${projectPath}`)) + console.error(e) + process.exit(1) + } + } + + // create the the morphir.json + const morphirJson = JSON.stringify( + { + name: name, + sourceDirectory: 'src' + }, + null, + 4 + ) + const morphirJsonPath = path.join(projectPath, 'morphir.json') + try { + await writeFile(morphirJsonPath, morphirJson) + } catch (error) { + console.log(chalk.red(`Could not create morphir.json`)) + console.error(error) + process.exit(1) + } + + // create the src directory + const srcDir = path.join(projectPath, 'src') + try { + mkdir(srcDir) + } catch (error) { + console.log(chalk.red(`Failed to create directory: ${srcDir}`)) + console.error(error) + process.exit(1) + } + + console.log() + console.log(chalk.blue('-- ALL DONE --------------------------------------------------\n')) + }) + +/** + * Creates suggestions for use based on their inputs. + * Performs some basic string cleanup before creating combinations. + * + * @param input original user input + * @returns comma separated string of suggestions. + */ +function getSuggestions(input: string): string { + const noLeadingDigits = input.replace(/^(\d*\s*\d*)/, '').trim() + const capitalized = noLeadingDigits[0].toUpperCase() + noLeadingDigits.substring(1) + const suggestions = new Set([capitalized.replace(' ', ''), capitalized.replace(' ', '.')]) + return [...suggestions].join(', ') +} diff --git a/cli2/morphir-make.ts b/cli2/morphir-make.ts index 9a34c3f01..0ac649a64 100644 --- a/cli2/morphir-make.ts +++ b/cli2/morphir-make.ts @@ -15,9 +15,10 @@ program .option('-p, --project-dir ', 'Root directory of the project where morphir.json is located.', '.') .option('-o, --output ', 'Target file location where the Morphir IR will be saved.', 'morphir-ir.json') .option('-t, --types-only', 'Only include type information in the IR, no values.', false) + .option('-i, --indent-json', 'Use indentation in the generated JSON file.', false) .parse(process.argv) const dirAndOutput = program.opts() // run make -make( dirAndOutput.projectDir, dirAndOutput ) \ No newline at end of file +make(dirAndOutput.projectDir, dirAndOutput) \ No newline at end of file diff --git a/cli2/morphir-scala-gen.ts b/cli2/morphir-scala-gen.ts index c872a9075..417e44c31 100644 --- a/cli2/morphir-scala-gen.ts +++ b/cli2/morphir-scala-gen.ts @@ -116,7 +116,7 @@ program .option('-e, --target-version ', 'Language version to Generate.', '2.11') .option('-c, --copy-deps', 'Copy the dependencies used by the generated code to the output path.', false) .option('-m, --limitToModules ', 'Limit the set of modules that will be included.', '') - .option('-s, --include-codecs ', 'Generate the scala codecs as well', false) + .option('-s, --include-codecs ', 'Generate the scala codecs as well', false) .option('--generate-test-generic', 'Generate generic test cases from morphir tests that can be used for testing', false) .option('--generate-test-scalatest', 'Generate runnable scalatest test cases', false) .parse(process.argv) diff --git a/cli2/morphir-snowpark-gen.ts b/cli2/morphir-snowpark-gen.ts new file mode 100644 index 000000000..f60550fab --- /dev/null +++ b/cli2/morphir-snowpark-gen.ts @@ -0,0 +1,146 @@ +#!/usr/bin/env node + +// NPM imports +import * as fs from "fs"; +import path from 'path'; +import { Command } from 'commander' +import cli = require('./cli') +import * as util from 'util' + +const fsWriteFile = util.promisify(fs.writeFile); +const fsMakeDir = util.promisify(fs.mkdir); +const fsReadFile = util.promisify(fs.readFile); + +const worker = require("./../Morphir.Elm.CLI").Elm.Morphir.Elm.CLI.init(); + +interface CommandOptions { + /** + * Name of the decorations file to load + */ + decorations?: string; + + /** + * Internal property used to send the contents of the decorations file to the Elm code. + */ + decorationsObj?: Array<{ [key: string]: Array }>; + limitToModules?: string; + includeCodecs?: boolean; + target?: string; +} + +function copyRedistributables(outputPath: string) { + const copyFiles = (src: string, dest: string) => { + const sourceDirectory: string = path.join( + path.dirname(__dirname), + "redistributable", + src + ); + if (fs.existsSync(sourceDirectory)) { + fs.cpSync(sourceDirectory, outputPath, { recursive: true, errorOnExist: false }); + } else { + console.warn(`WARNING: Cannot find directory ${sourceDirectory}`); + } + }; + copyFiles("Snowpark", outputPath); +} + +const generate = async ( + options: CommandOptions, + ir: string +): Promise => { + return new Promise((resolve, reject) => { + worker.ports.jsonDecodeError.subscribe((err: any) => { + reject(err); + }); + worker.ports.generateResult.subscribe(([err, ok]: any) => { + if (err) { + reject(err); + } else { + resolve(ok); + } + }); + + worker.ports.generate.send([options, ir, []]); + }); +}; + +const gen = async ( + input: string, + outputPath: string, + options: CommandOptions +) => { + await fsMakeDir(outputPath, { + recursive: true, + }); + + // Add default values for these options + options.limitToModules = ''; + options.includeCodecs = false; + options.target = 'Snowpark' + + if (options.decorations) { + if (fs.existsSync(path.resolve(options.decorations))) { + let fileContents = await fsReadFile(path.resolve(options.decorations)); + options.decorationsObj = JSON.parse(fileContents.toString()); + } else { + console.warn(`WARNING: The specified decorations file do not exist: ${options.decorations}`) + } + } + + const morphirIrJson: Buffer = await fsReadFile(path.resolve(input)); + const generatedFiles: string[] = await generate( + options, + JSON.parse(morphirIrJson.toString()) + ); + + const writePromises = generatedFiles.map( + async ([[dirPath, fileName], content]: any) => { + const fileDir: string = dirPath.reduce( + (accum: string, next: string) => path.join(accum, next), + outputPath + ); + const filePath: string = path.join(fileDir, fileName); + + if (await cli.fileExist(filePath)) { + const existingContent: Buffer = await fsReadFile(filePath); + + if (existingContent.toString() !== content) { + await fsWriteFile(filePath, content); + console.log(`UPDATE - ${filePath}`); + } + } else { + await fsMakeDir(fileDir, { + recursive: true, + }); + await fsWriteFile(filePath, content); + console.log(`INSERT - ${filePath}`); + } + } + ); + const filesToDelete = await cli.findFilesToDelete(outputPath, generatedFiles); + const deletePromises = filesToDelete.map(async (fileToDelete: string) => { + console.log(`DELETE - ${fileToDelete}`); + return fs.unlinkSync(fileToDelete); + }); + copyRedistributables(outputPath); + return Promise.all(writePromises.concat(deletePromises)); +}; + +const program = new Command() +program + .name('morphir snowpark-gen') + .description('Generate Scala with Snowpark code from Morphir IR') + .option('-i, --input ', 'Source location where the Morphir IR will be loaded from.', 'morphir-ir.json') + .option('-o, --output ', 'Target location where the generated code will be saved.', './dist') + .option('-dec, --decorations ', 'JSON file with decorations') + + .parse(process.argv) + +gen(program.opts().input, path.resolve(program.opts().output), program.opts()) + .then(() => { + console.log('Done') + }) + .catch((err) => { + console.log(err) + process.exit(1) + }) diff --git a/cli2/morphir.ts b/cli2/morphir.ts index 56fb201c7..7c610ebf2 100644 --- a/cli2/morphir.ts +++ b/cli2/morphir.ts @@ -11,10 +11,12 @@ const program = new Command() program .version(packageJson.version, '-v, --version') .command('make', 'Translate Elm sources to Morphir IR') - .command('scala-gen','Generate scala code from Morphir IR') + .command('scala-gen', 'Generate scala code from Morphir IR') .command('json-schema-gen', 'Generate Json Schema from the Morphir IR') + .command('snowpark-gen','Generate Scala with Snowpark code from Morphir IR') .command('stats', 'Collect morphir features used in a model into a document') .command('dockerize', 'Creates a docker image of a Morphir IR and Morphir Develop') .command('test-coverage', 'Generates report on number of branches in a Morphir value and TestCases covered') .command('generate-test-data', 'Creates a docker image of a Morphir IR and Morphir Develop') + .command('init', 'Launches an interactive session to initialize a new morphir project.') .parse(process.argv) \ No newline at end of file diff --git a/cli2/src/Morphir/Elm/CLI.elm b/cli2/src/Morphir/Elm/CLI.elm index 3532cf91d..972304a4f 100644 --- a/cli2/src/Morphir/Elm/CLI.elm +++ b/cli2/src/Morphir/Elm/CLI.elm @@ -138,6 +138,12 @@ update msg model = process : Msg -> Cmd Msg process msg = + let + withDefaultDeps packageDist = + case packageDist of + Library packageName dependencies packageDef -> + Library packageName (Dict.union Frontend.defaultDependencies dependencies) packageDef + in case msg of BuildFromScratch jsonInput -> let @@ -274,7 +280,7 @@ process msg = |> Result.andThen (\packageDist -> Decode.decodeValue - (TestCodec.decodeTestSuite packageDist) + (TestCodec.decodeTestSuite (packageDist |> withDefaultDeps)) testSuiteJson ) in @@ -282,14 +288,10 @@ process msg = Result.map3 (\options packageDist maybeTestSuite -> let - enrichedDistro = - case packageDist of - Library packageName dependencies packageDef -> - Library packageName (Dict.union Frontend.defaultDependencies dependencies) packageDef fileMap : Result Encode.Value FileMap fileMap = - mapDistribution options maybeTestSuite enrichedDistro + mapDistribution options maybeTestSuite (packageDist |> withDefaultDeps) in fileMap ) @@ -313,14 +315,10 @@ process msg = case packageDistroResult of Ok packageDist -> let - enrichedDistro = - case packageDist of - Library packageName dependencies packageDef -> - Library packageName (Dict.union Frontend.defaultDependencies dependencies) packageDef fileMap : FileMap fileMap = - Stats.collectFeaturesFromDistribution enrichedDistro + Stats.collectFeaturesFromDistribution (packageDist |> withDefaultDeps) in fileMap |> Ok |> encodeResult Encode.string encodeFileMap |> statsResult @@ -354,11 +352,11 @@ process msg = case testSuiteResult of Ok testSuite -> accesscontrolledModDef.value - |> getBranchCoverage ( packageName, modName ) packageDistro testSuite + |> getBranchCoverage ( packageName, modName ) (packageDistro |> withDefaultDeps) testSuite Err err -> accesscontrolledModDef.value - |> getBranchCoverage ( packageName, modName ) packageDistro Dict.empty + |> getBranchCoverage ( packageName, modName ) (packageDistro |> withDefaultDeps) Dict.empty ) |> List.map encodeTestCoverageResult |> (\lstValues -> diff --git a/cli2/src/Morphir/Elm/Target.elm b/cli2/src/Morphir/Elm/Target.elm index 4b52744da..ef9f8122a 100644 --- a/cli2/src/Morphir/Elm/Target.elm +++ b/cli2/src/Morphir/Elm/Target.elm @@ -16,6 +16,7 @@ import Morphir.Scala.Spark.Backend import Morphir.SpringBoot.Backend as SpringBoot import Morphir.SpringBoot.Backend.Codec import Morphir.TypeScript.Backend +import Morphir.Snowpark.Backend @@ -30,7 +31,7 @@ type BackendOptions | TypeScriptOptions Morphir.TypeScript.Backend.Options | SparkOptions Morphir.Scala.Spark.Backend.Options | JsonSchemaOptions JsonSchemaBackend.Options - + | SnowparkOptions Morphir.Snowpark.Backend.Options type alias Errors = List String @@ -54,6 +55,9 @@ decodeOptions gen = Ok "Spark" -> Decode.map SparkOptions (Decode.succeed Morphir.Scala.Spark.Backend.Options) + Ok "Snowpark" -> + Decode.map SnowparkOptions Morphir.Snowpark.Backend.decodeOptions + Ok "JsonSchema" -> Decode.map (\options -> JsonSchemaOptions options) Morphir.JsonSchema.Backend.Codec.decodeOptions @@ -83,6 +87,9 @@ mapDistribution backendOptions morphirTestSuite dist = SparkOptions options -> Ok <| Morphir.Scala.Spark.Backend.mapDistribution options dist + SnowparkOptions options -> + Ok <| Morphir.Snowpark.Backend.mapDistribution options dist + JsonSchemaOptions options -> JsonSchemaBackend.mapDistribution options dist |> Result.mapError Morphir.JsonSchema.Backend.Codec.encodeErrors diff --git a/docs/snowpark/snowpark-backend-generation.md b/docs/snowpark/snowpark-backend-generation.md new file mode 100644 index 000000000..46bcea0a2 --- /dev/null +++ b/docs/snowpark/snowpark-backend-generation.md @@ -0,0 +1,552 @@ +--- +id: snowpark-backend-generation +title: Snowpark backend generation +--- + +# Generation patterns and strategies + +The **Snowpark** backend supports two main code generation strategies: + +- Generating code that manipulates [DataFrame](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes) expressions +- Generating "plain" Scala code + +The backend identifies a series of patterns for deciding which strategy is used to convert a function. These patterns apply to the way types and function are defined. + +## Type definition patterns + +Type definitions in the input **Morphir IR** are classified using the following patterns: + +### Records that represent tables + +Records are classified as "representing a table definition" according to the types of its members. A type that is compatible with a [DataFrame](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes) is considered to fall in this category. These types are: + +- A basic datatype + - Int + - Float + - Bool + - String +- A [custom type](https://guide.elm-lang.org/types/custom_types.html) +- A [Maybe](https://package.elm-lang.org/packages/elm/core/latest/Maybe) type used with a DataFrame compatible type +- An [alias](https://guide.elm-lang.org/types/type_aliases) of a DataFrame compatible type + +An example of one of these records is the following: + +```elm +type alias Employee = + { firstName : String + , lastName : String + } +``` + +The **Snowpark** backend generates the following code for each type definition: + +```scala + trait Employee { + + def firstName: com.snowflake.snowpark.Column + + def lastName: com.snowflake.snowpark.Column + + } + + object Employee extends Employee{ + + def firstName: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.col("firstName") + + def lastName: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.col("lastName") + + val schema = com.snowflake.snowpark.types.StructType( + com.snowflake.snowpark.types.StructField( + "FirstName", + com.snowflake.snowpark.types.StringType, + false + ), + com.snowflake.snowpark.types.StructField( + "LastName", + com.snowflake.snowpark.types.StringType, + false + ) + ) + + def createEmptyDataFrame( + session: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = + emptyDataFrameCache.getOrElseUpdate( + true, + session.createDataFrame( + Seq( + + ), + schema + ) + ) + + val emptyDataFrameCache: scala.collection.mutable.HashMap[Boolean, com.snowflake.snowpark.DataFrame] = new scala.collection.mutable.HashMap( + + ) + + } + + class EmployeeWrapper( + df: com.snowflake.snowpark.DataFrame + ) extends Employee{ + + def firstName: com.snowflake.snowpark.Column = + df("firstName") + + def lastName: com.snowflake.snowpark.Column = + df("lastName") + + } +``` + +This code includes: + +- A [trait](https://docs.scala-lang.org/tour/traits.html) with the definitions of the columns +- A [singleton object](https://docs.scala-lang.org/tour/singleton-objects.html) implementing the trait with the column definitions and an utility method to create an empty DataFrame for the current record +- A column wrapper class implementing the previous trait and giving access to the specific columns of a DataFrame + +### Records representing Scala classes + +Records that contain fields that are not compatible with table column definitions are classified as "complex" and are generated as [Scala case classes](https://docs.scala-lang.org/tour/case-classes.html). + +Examples of these types are: + +- Lists +- Other record definitions +- Functions + +For example: + +```elm +type alias DataFromCompany + = + { employees : List Employee + , departments: List Department + } +``` + +This backend generates the following class for this record definition: + +```scala + case class DataFromCompany( + employees: com.snowflake.snowpark.DataFrame, + departments: com.snowflake.snowpark.DataFrame + ){} +``` + +### Types representing DataFrames + +This backend considers lists of "records representing tables" as a [**Snowpark** DataFrame](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes). For example: + + +```elm +getEmployeesWithLastName : String -> List Employee -> List Employee +getEmployeesWithLastName lastName employees = + employees + |> List.filter (\employee -> employee.lastName == lastName) +``` + +In this case references to `List Employee` are converted to DataFrames: + +```scala + def getEmployeesWithLastName( + lastName: com.snowflake.snowpark.Column + )( + employees: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val employeesColumns: myModel.Basic.Employee = new myModel.Basic.EmployeeWrapper(employees) + + employees.filter((employeesColumns.lastName) === (lastName)) + } +``` + +## Custom types + +Two patterns are used to process [custom types](https://guide.elm-lang.org/types/custom_types.html). These patterns depend on the presence of parameters for type constructors. + +### 1. Custom types without data + +Custom types that define constructors without parameters are treated as a `String` (or `CHAR`, `VARCHAR`) column. + +For example: + +```elm +type CardinalDirection + = North + | South + | East + | West + +type alias Directions = + { + id : Int, + direction : CardinalDirection + } + +northDirections : List Directions -> List Directions +northDirections dirs = + dirs + |> List.filter (\e -> e.direction == North) +``` + +In this case it is assumed that the code stored in the `Directions` table has a column of type `VARCHAR` or `CHAR` with text with the name of field. For example: + +| ID | DIRECTION | +|-----|------------| +| 10 | 'North' | +| 23 | 'East' | +| 43 | 'South' | + +As a convenience a Scala object is generated with the definition of the possible values: + +```Scala +object CardinalDirection{ + +def East: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("East") + +def North: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("North") + +def Sourth: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("South") + +def West: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("West") + +} +``` +Notice the use of [lit](https://docs.snowflake.com/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/functions$.html#lit(literal:Any):com.snowflake.snowpark.Column) to indicate that we expect a literal string value for each constructor. + +This object is used where the value of the possible constructors is used. For example for the definition of `northDirections` above the comparison with `North` is generated as follows: + +```Scala + def northDirections( + dirs: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val dirsColumns: myModel.Basic.Directions = new myModel.Basic.DirectionsWrapper(dirs) + + dirs.filter((dirsColumns.direction) === (myModel.Basic.CardinalDirection.North)) + } +``` + +### 2. Custom types with data + +This backend uses an [OBJECT column](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#object) to represent custom types that have constructors with parameters. Using this kind of columns allows storing different options allowed by the custom type definition. The encoding of a column is defined as follows: + +- Values are encoded as a `JSON` object +- A special property of this object called `"__tag"` is used to determine which variant is used in the current value +- All the parameters in order are stored in properties called `field0`, `field1`, `field2` ... `fieldN` + +Given the following custom type definition: + +```elm +type TimeRange = + Zero + | Seconds Int + | MinutesAndSeconds Int Int + +type alias TasksEstimations = + { + taskId : Int, + estimation : TimeRange + } +``` + +The data for `TaskEstimations` is expected to be stored in a table using an `OBJECT` column: + +| TASKID | ESTIMATION | +|--------|-------------------------------------------------------------------| +| 10 | `{ "__tag": "Zero" }` | +| 20 | `{ "__tag": "MinutesAndSeconds", "field0": 10, "field1": 20 }` | +| 30 | `{ "__tag": "Seconds", "field0": 2 }` | + +Pattern matching operations that manipulate values of this type are generated as operations that process JSON expressions following this pattern. + +For example: + +```elm +getTasksEstimationInSeconds : List TasksEstimations -> List { seconds : Int } +getTasksEstimationInSeconds tasks = + tasks + |> List.map (\t -> + let + seconds = + case t.estimation of + Zero -> + 0 + Seconds s -> + s + MinutesAndSeconds mins secs -> + mins*60 + secs + in + { seconds = seconds }) + +``` + +This code is generated as: + +```scala + def getTasksEstimationInSeconds( + tasks: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val tasksColumns: myModel.Basic.TasksEstimations = new myModel.Basic.TasksEstimationsWrapper(tasks) + + tasks.select(com.snowflake.snowpark.functions.when( + (tasksColumns.estimation("__tag")) === (com.snowflake.snowpark.functions.lit("Zero")), + com.snowflake.snowpark.functions.lit(0) + ).when( + (tasksColumns.estimation("__tag")) === (com.snowflake.snowpark.functions.lit("Seconds")), + tasksColumns.estimation("field0") + ).when( + (tasksColumns.estimation("__tag")) === (com.snowflake.snowpark.functions.lit("MinutesAndSeconds")), + ((tasksColumns.estimation("field0")) * (com.snowflake.snowpark.functions.lit(60))) + (tasksColumns.estimation("field1")) + ).as("seconds")) + } +``` + +#### 3. Strategy for generating `Maybe` types + +The [Maybe a](https://package.elm-lang.org/packages/elm/core/latest/Maybe) type is assumed to be a nullable database value. This means that the data is expected to be stored as follows: + +| Elm value | Value stored in the Database | +|--------------|-------------------------------| +| `Just 10` | `10` | +| `Nothing` | `NULL` | + + +## Function definition patterns + +These patterns are based on the input and return types of a function. Two strategies are used: using DataFrame expressions or using Scala expressions. The following sections have more details. + +### Code generation using DataFrame expressions manipulation + +For functions that receive or return DataFrames, simple types, or records the generation strategy is to generate DataFrame expressions for example: + +Given the following functions: + +```elm +checkLastName : String -> Employee -> Bool +checkLastName name employee = + if employee.lastName == name then + True + else + False + +getEmployeeWithLastName : String -> List Employee -> List Employee +getEmployeeWithLastName lastName employees = + employees + |> List.filter (\e -> checkLastName lastName e) +``` + +In this case the backend generates the following code: + +```scala + def checkLastName( + name: com.snowflake.snowpark.Column + )( + employee: myModel.Basic.Employee + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (employee.lastName) === (name), + com.snowflake.snowpark.functions.lit(true) + ).otherwise(com.snowflake.snowpark.functions.lit(false)) + + def getEmployeeWithLastName( + lastName: com.snowflake.snowpark.Column + )( + employees: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val employeesColumns: myModel.Basic.Employee = new myModel.Basic.EmployeeWrapper(employees) + + employees.filter(myModel.Basic.checkLastName(lastName)(employeesColumns)) + } +``` + +Notice that language constructs are converted to DataFrame expression. For example in the way the `if` expression was converted to a combination of [`when`](https://docs.snowflake.com/ko/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/functions$.html#when(condition:com.snowflake.snowpark.Column,value:com.snowflake.snowpark.Column):com.snowflake.snowpark.CaseExpr) and [`otherwise`](https://docs.snowflake.com/ko/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/CaseExpr.html#otherwise(value:com.snowflake.snowpark.Column):com.snowflake.snowpark.Column) calls. + +### Pattern for functions from values to lists of records + +If the function doesn't receive a DataFrame but produces lists of records, the strategy for code generation changes. In this case the pattern assumes that an array of semi-structured objects is being created instead of a DataFrame. + +For example: + +```elm +type alias Department = { + name : String + } + +type Buildings + = B1 + | B2 + | B3 + +type alias DeptBuildingClassification = + { + deptName : String, + building : Buildings + } + +classifyDepartment : Department -> List DeptBuildingClassification +classifyDepartment dept = + if List.member dept.name ["HR", "IT"] then + [ { deptName = dept.name + , building = B1 } ] + else if String.startsWith "DEVEL" dept.name then + [ { deptName = dept.name + , building = B2 } + , { deptName = dept.name + , building = B3 } ] + else + [ ] + +getBuildings : List Department -> List DeptBuildingClassification +getBuildings depts = + depts + |> List.concatMap (\e -> classifyDepartment e) +``` + +Notice the function `classifyDepartment` which generates a list of records but does not receive a list of records. In this case the code is generated as: + +```scala + def classifyDepartment( + dept: myModel.Basic.Department + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + dept.name.in(Seq( + com.snowflake.snowpark.functions.lit("HR"), + com.snowflake.snowpark.functions.lit("IT") + )), + com.snowflake.snowpark.functions.array_construct(com.snowflake.snowpark.functions.array_construct( + dept.name, + myModel.Basic.Buildings.B1 + )) + ).otherwise(com.snowflake.snowpark.functions.when( + com.snowflake.snowpark.functions.startswith( + dept.name, + com.snowflake.snowpark.functions.lit("DEVEL") + ), + com.snowflake.snowpark.functions.array_construct( + com.snowflake.snowpark.functions.array_construct( + dept.name, + myModel.Basic.Buildings.B2 + ), + com.snowflake.snowpark.functions.array_construct( + dept.name, + myModel.Basic.Buildings.B3 + ) + ) + ).otherwise(com.snowflake.snowpark.functions.array_construct( + + ))) + + def getBuildings( + depts: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val deptsColumns: myModel.Basic.Department = new myModel.Basic.DepartmentWrapper(depts) + + depts.select(myModel.Basic.classifyDepartment(myModel.Basic.Department).as("result")).flatten(com.snowflake.snowpark.functions.col("result")).select( + com.snowflake.snowpark.functions.as_char(com.snowflake.snowpark.functions.col("value")(0)).as("deptName"), + com.snowflake.snowpark.functions.col("value")(1).as("building") + ) + } +``` + +### Code generation using Scala expressions + +When a function receives *"complex"* types as parameters the strategy is changed to use a Scala expression approach. + +For example: + +```elm +type alias EmployeeSal = + { firstName : String + , lastName : String + , salary : Float + } + + +type alias DataForCompany + = + { employees : List EmployeeSal + , departments: List Department + } + +avgSalaries : DataForCompany -> Float +avgSalaries companyData = + let + sum = companyData.employees + |> List.map (\e -> e.salary) + |> List.sum + count = companyData.employees + |> List.length + in + sum / (toFloat count) +``` + +In this case code for `avgSalaries` is going to perform a Scala division operation with the result of two DataFrame operations: + +```Scala + def avgSalaries( + companyData: myModel.Basic.DataForCompany + )( + implicit sfSession: com.snowflake.snowpark.Session + ): Double = { + val sum = companyData.employees.select(myModel.Basic.EmployeeSal.salary.as("result")).select(com.snowflake.snowpark.functions.coalesce( + com.snowflake.snowpark.functions.sum(com.snowflake.snowpark.functions.col("result")), + com.snowflake.snowpark.functions.lit(0) + )).first.get.getDouble(0) + + val count = companyData.employees.count + + (sum) / (count.toDouble) + } +``` + +Code generation for this strategy is meant to be used for code that manipulates the result of performing DataFrame operations. At this moment its coverage is very limited. + +## Creation of empty DataFrames + +Creating an empty list of table-like records is interpreted as creating an empty DataFrame. For example: + +```elm +createDataForTest : List Employee -> DataFromCompany +createDataForTest emps = + { employees = emps , departments = [] } +``` + +In this case the code is generated as follows: + +```scala + def createDataForTest( + emps: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): mymodel.Basic.DataFromCompany = { + val empsColumns: mymodel.Basic.Employee = new mymodel.Basic.EmployeeWrapper(emps) + + mymodel.Basic.DataFromCompany( + employees = emps, + departments = mymodel.Basic.Department.createEmptyDataFrame(sfSession) + ) + } +``` + +Notice that this is the main reason for having an `implicit` with the [Session object](https://docs.snowflake.com/en/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/Session.html). diff --git a/docs/snowpark/snowpark-backend-joins.md b/docs/snowpark/snowpark-backend-joins.md new file mode 100644 index 000000000..ab0b9fd08 --- /dev/null +++ b/docs/snowpark/snowpark-backend-joins.md @@ -0,0 +1,178 @@ +# Join support in Snowpark + +Integrating data from disparate sources is a common necessity, often arising from the need to establish relationships between datasets originating from different sources. In the dynamic landscape of data analysis, the process of merging information plays a pivotal role in gaining comprehensive insights. + +If you wish to achieve this functionality in Morphir, you would implement something similar to the following example: + +```elm +simpleInnerJoin : List TypeA -> List TypeB -> List {idA: Int, idB: Int} +simpleInnerJoin dataSetA dataSetB = + dataSetA + |> innerJoin dataSetB + ( \a b -> a.id == b.id ) + |> List.map (\ (x, y) -> + { idA = x.id + , idB = y.id + }) +``` + +The `simpleInnerJoin` example illustrates how to perform an *inner join* operation between two datasets, dataSetA and dataSetB, represented as lists of types TypeA and TypeB respectively. In this case, the join is based on a specific condition: equality between the `id` properties of elements in dataSetA and dataSetB. + +The `innerJoin` function (provided for the [Morphir.SDK](https://package.elm-lang.org/packages/finos/morphir-elm/latest/Morphir-SDK-List#innerJoin)) facilitates this join, taking the equality condition provided in the lambda function `(\a b -> a.id == b.id)`. + +Subsequently, the List.map function is used to project the results of the join. The lambda function `(\(x, y) -> { idA = x.id, idB = y.id })` maps each pair of results (x, y) to a new data type `{ idA : Int, idB : Int }`, where `idA` represents the `id` value in dataSetA and `idB` represents the `id` value in dataSetB. + +This example demonstrates how Morphir in Elm can be used concisely and expressively to perform join and projection operations, providing a solid foundation for efficient data manipulation. + +## Joins in Snowpark + +In Snowpark, support is provided for specific scenarios that follow the join pattern. You can visit the [documentation](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes#joining-dataframes) here. + +### Inner Join + +If you have this code in Elm using the `innerJoin` function: + +```elm +simpleInnerJoin : List TypeA -> List TypeB -> List {idA: Int, idB: Int} +simpleInnerJoin dataSetA dataSetB = + dataSetA + |> innerJoin dataSetB + ( \a b -> a.id == b.id ) + |> List.map (\ (x, y) -> + { idA = x.id + , idB = y.id + }) +``` + +The transformation to Snowpark will be: + +```Scala + def simpleInnerJoin + (dataSetA: com.snowflake.snowpark.DataFrame) + (dataSetB: com.snowflake.snowpark.DataFrame) + (implicit sfSession: com.snowflake.snowpark.Session): com.snowflake.snowpark.DataFrame = { + val dataSetAColumns: deparments.Joins.TypeA = new deparments.Joins.TypeAWrapper(dataSetA) + val dataSetBColumns: deparments.Joins.TypeB = new deparments.Joins.TypeBWrapper(dataSetB) + + dataSetA.join( + dataSetB, + (dataSetAColumns.id) === (dataSetBColumns.id), + "inner" + ).select( + dataSetAColumns.id.alias("idA"), + dataSetBColumns.id.alias("idB") + ) + } +``` + +You can notice that `innerJoin` function from **Morphir.SDK** is transform to `join` function of **Snowpark** passing the argument `inner` to choose the join type. + +The projection is changed to a **Snowpark select** to return a dataframe with the selected columns. + +### Left Join + +The `leftJoin` function is similar to `innerJoin`. You can find the documentation of *Morphir.SDK* [here](https://package.elm-lang.org/packages/finos/morphir-elm/latest/Morphir-SDK-List#leftJoin). The difference is that the `leftJoin` returns a `List ( a, Maybe b)` instead, so in the projection you must to return a maybe value: + +```elm +simpleLeftJoin : List TypeA -> List TypeB -> List {x: Int, y: Maybe Int} +simpleLeftJoin dataSetA dataSetB = + dataSetA + |> leftJoin dataSetB + ( \a b -> a.id == b.id ) + |> List.map (\ (x, y) -> + { x = x.id + , y = Maybe.map (\t -> t.id) y + }) +``` + +The transformation to Snowpark will be: + +```Scala +def simpleLeftJoin + (dataSetA: com.snowflake.snowpark.DataFrame) + (dataSetB: com.snowflake.snowpark.DataFrame) + (implicit sfSession: com.snowflake.snowpark.Session): com.snowflake.snowpark.DataFrame = { + val dataSetAColumns: deparments.Joins.TypeA = new deparments.Joins.TypeAWrapper(dataSetA) + val dataSetBColumns: deparments.Joins.TypeB = new deparments.Joins.TypeBWrapper(dataSetB) + + dataSetA.join( + dataSetB, + (dataSetAColumns.id) === (dataSetBColumns.id), + "left" + ).select( + dataSetAColumns.id.alias("x"), + dataSetBColumns.id.alias("y") + ) + } +``` + +In Snowpark, when employing a join operation, it is important to note that columns with `null` values may be encountered when performing a join operation. Consequently, you might observe that the `select` projection simply yields a basic column that could potentially include `null` values. For more information about Snowpark and `Joins` you can see [this link](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes#joining-dataframes). + +### Multiple Joins + +In Morphir, you have the flexibility to use two consecutive joins to combine data from three different sources. To achieve this, you can employ one join after another and craft a projection to obtain the desired data. This approach allows you to seamlessly integrate information from multiple datasets, enhancing the versatility of your data manipulation operations, for example: + +```elm +multipleJoin : List TypeA -> List TypeB -> List TypeC -> List {idA: Int, idB: Int, idC: Int} +multipleJoin dataSetA dataSetB dataSetC = + dataSetA + |> innerJoin dataSetB (\a b -> a.id == b.id ) + |> innerJoin dataSetC (\(x, y) z -> x.id == z.id ) + |> List.map (\ ((a, b), c) -> + { idA = a.id + , idB = b.id + , idC = c.id + }) +``` + +The transformation to Snowpark will be: + +```Scala + def multipleJoin( + dataSetA: com.snowflake.snowpark.DataFrame + )( + dataSetB: com.snowflake.snowpark.DataFrame + )( + dataSetC: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val dataSetAColumns: deparments.Joins.TypeA = new deparments.Joins.TypeAWrapper(dataSetA) + + val dataSetBColumns: deparments.Joins.TypeB = new deparments.Joins.TypeBWrapper(dataSetB) + + val dataSetCColumns: deparments.Joins.TypeC = new deparments.Joins.TypeCWrapper(dataSetC) + + dataSetA.join( + dataSetB, + (dataSetAColumns.id) === (dataSetBColumns.id), + "inner" + ).join( + dataSetC, + (dataSetAColumns.id) === (dataSetCColumns.id), + "inner" + ).select( + dataSetAColumns.id.alias("idA"), + dataSetBColumns.id.alias("idB"), + dataSetCColumns.id.alias("idC") + ) + } +``` + +In Snowpark, you can perform the union of two or more join functions, enabling support for multiple joins within a single query. In the final part of the query, a projection is generated using a select statement, which selects the desired columns to be included in the resulting DataFrame. + +### Requirements + +It is essential to note that for these patterns to be transformed, they must meet certain requirements: + +1. Return a Projection as a List of a Record: + +- The join pattern should result in a projection that is a list of a record. + +2. Function Parameters Representing a Table: + +- The parameters of the function must be a list of records representing a table. For more information, refer to the Snowpark backend types section. For more information related to the `types` you can see [this link](snowpark-backend-types.md). + +3. Supported Join Functions: + +- Currently, the Snowpark backend supports the innerJoin and leftJoin functions from [Morphir.SDK](https://package.elm-lang.org/packages/finos/morphir-elm/latest/Morphir-SDK-List#leftJoin). \ No newline at end of file diff --git a/docs/snowpark/snowpark-backend-limitations.md b/docs/snowpark/snowpark-backend-limitations.md new file mode 100644 index 000000000..b7042cb40 --- /dev/null +++ b/docs/snowpark/snowpark-backend-limitations.md @@ -0,0 +1,133 @@ +--- +id: snowpark-backend-limitations +title: Snowpark backend limitations +--- + +# Limitations of the Snowpark backend + +The goal of the Snowpark backend is to generate expressions that can take advantage of the **Snowpark** infrastructure. Because of this, there are several language practices that are valid in `Mophir-IR/Elm` that are not supported by this backend. When possible a warning is generated in the code or in the `GenerationReport.md` file. + +Some of these limitations include: + +## Recursive functions manipulating dataframe expressions + +This backend tries to generate as many dataframe expressions as possible. That is why many functions are generated as Scala functions that generate dataframe expression (or [Column](https://docs.snowflake.com/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/Column.html) objects). For example: + +For example: + +```elm +double : Int -> Int +double x = + if x == 0 then + 0 + else + x * x +``` + +Is converted to: + +```elm + def double( + x: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (x) === (com.snowflake.snowpark.functions.lit(0)), + com.snowflake.snowpark.functions.lit(0) + ).otherwise((x) * (x)) +``` + +As shown above this function is going to return a `Column` instance. This object represents the actual expression tree that is processed by the **Snowpark** library. This transformation makes it impossible to convert functions that make recursive calls. For example: + +```elm +factorial : Int -> Int +factorial n = + if n == 0 then + 1 + else + n * (factorial (n - 1)) +``` + +The generated Scala code looks like this: + +```scala + def factorial( + n: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (n) === (com.snowflake.snowpark.functions.lit(0)), + com.snowflake.snowpark.functions.lit(1) + ).otherwise((n) * (mymodel.Basic.factorial((n) - (com.snowflake.snowpark.functions.lit(1))))) +``` + +Since this code is composed only of nested function calls, there is nothing preventing the execution of the recursive call. This + +```bash +java.lang.StackOverflowError + com.snowflake.snowpark.Column.$eq$eq$eq(Column.scala:269) + mymodel.Basic$.factorial(Basic.scala:751) + mymodel.Basic$.factorial(Basic.scala:753) + mymodel.Basic$.factorial(Basic.scala:753) + mymodel.Basic$.factorial(Basic.scala:753) + mymodel.Basic$.factorial(Basic.scala:753) + mymodel.Basic$.factorial(Basic.scala:753) + mymodel.Basic$.factorial(Basic.scala:753) + mymodel.Basic$.factorial(Basic.scala:753) + ... +``` + +## Code that do not manipulate lists of table-like records + +To take advantage of this backend, the code being processed has to manipulate lists of table-like records (ex. with fields of only basic). These structure are identified as [DataFrames](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes). + + +## Code that do not follow the supported patterns + +The backend assumes some conventions and patterns to determine how to interpret the code that is being processed. These patterns are described in [snowpark-backend-generation](snowpark-backend-generation.md). + + +## Unsupported elements + +There may be situations when this backend cannot convert an element from the **Morphir-IR** . Depending on the scenario the backend generates default expressions or types to indicate that something was not converted. + +For example, given that there is no support for the `List.range` function we can try to convert the following snippet: + +```elm +myFunc2: Int -> Int +myFunc2 x = + let + y = x + 1 + z = y + 1 + r = List.range 10 20 + in + x + y + z +``` + +The resulting code is the following: + +```scala + def myFunc2( + x: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = { + val y = (x) + (com.snowflake.snowpark.functions.lit(1)) + + val z = (y) + (com.snowflake.snowpark.functions.lit(1)) + + val r = "Call not generated" + + ((x) + (y)) + (z) + } +``` + +Notice that the `"Call not generated"` expression was generated. Also, the `GenerationReport.md` file is going to include an error message for this function: + +```markdown +### MyModel:Basic:myFunc2 + +- Call to function not generated: Morphir.SDK:List:range +``` \ No newline at end of file diff --git a/docs/snowpark/snowpark-backend-overview.md b/docs/snowpark/snowpark-backend-overview.md new file mode 100644 index 000000000..bbd70a1fb --- /dev/null +++ b/docs/snowpark/snowpark-backend-overview.md @@ -0,0 +1,74 @@ +--- +id: snowpark-backend-overview +title: Snowpark backend overview +--- + +# Snowpark backend overview + +## Introduction + +**Morphir** is a system for capturing business logic in a [technology agnositic manner](https://morphir.finos.org/docs/intro/). Morphir has an intermediate representation ([Morphir IR](https://morphir.finos.org/docs/morphir-ir)) that is used to store this logic. The [Morphir-elm](https://github.com/finos/morphir-elm) tool provides several backends for transpiling **Morphir-IR** to different languages and platforms. + +The Morphir Snowpark backend for **Morphir-elm** generates [Scala](https://www.scala-lang.org/) code that uses the [Snowpark](https://docs.snowflake.com/en/developer-guide/snowpark/scala/index) API to represent operations expressed in **Morphir-IR**. [Snowflake Snowpark](https://docs.snowflake.com/en/developer-guide/snowpark/index) is an API for querying and processing data in a data pipeline. + +## An example + +The following [Elm](https://elm-lang.org/) code represents a query from the [Modeling for database developers](https://morphir.finos.org/docs/modeling-database-developers) section: + +```elm +query1 : List Trade -> List { product : Int, qty : Int } +query1 trades = + trades + |> List.filter (\t -> t.buySell == "S") + |> List.map + (\t -> + { product = t.productID + , qty = t.quantity + } + ) +``` + +The **Morphir-elm** Snowpark backend generates the following Scala code from this function definition: + +```scala + def query1( + trades: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val tradesColumns: mymodel.Basic.Trade = new mymodel.Basic.TradeWrapper(trades) + + trades.filter((tradesColumns.buySell) === (com.snowflake.snowpark.functions.lit("S"))).select( + tradesColumns.productID.as("product"), + tradesColumns.quantity.as("qty") + ) + } +``` + +## Snowpark backend and other backends + +As with other backends provided by the **Morphir-elm** tool, this backend can be used to generate code from **Morphir-IR** . The `gen -t Snowpark` options are used to activate it. + +![snowpark backend](snowpark-backend.svg) + +The goal of the Snowpark backend is to generate code that takes advantage of the [DataFrame API](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes). To do this, the backend analyses the code to [identify patterns of code](snowpark-backend-generation.md) in **Morphir-IR** that can be translated to use this API. + +There are programming practices do not adapt easily to DataFrame operations (for example recursive functions). In these cases the backend may not be able to generate useful code. This is one of the main differences with other backends such as the [Scala](https://morphir.finos.org/docs/scala-backend) or the [TypeScript](https://morphir.finos.org/docs/typescript-api) backends. See the [limitations](snowpark-backend-limitations.md) section for more information. + + + +## Using the generated code + +Code generated with this backend could be compiled and packaged into [JAR files](https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jarGuide.html) using any Scala or Java build tool like [Maven](https://docs.snowflake.com/en/developer-guide/snowpark/scala/setup-other-environments#using-the-snowpark-library-in-a-maven-project) or [sbt](https://docs.snowflake.com/en/developer-guide/snowpark/scala/quickstart-sbt#creating-a-new-scala-project-in-sbt). + +These packages can then be used to create standalone programs or Snowflake [stored procedures](https://docs.snowflake.com/en/developer-guide/snowpark/scala/creating-sprocs) or [functions](https://docs.snowflake.com/en/developer-guide/snowpark/scala/creating-udfs). It can also be used to explore code using Jupyter notebooks: + +![jupyter notebook scala](sp_jupyter_nb.png) + +## Customizing the output + +This backend supports customization by using [Morphir Decorations](https://morphir.finos.org/docs/decorations-users-guide). + +![inline decoration](sp_inline_decoration.png) + +More details in the [customization and execution section](snowpark-backend-using-and-customize.md). \ No newline at end of file diff --git a/docs/snowpark/snowpark-backend-types.md b/docs/snowpark/snowpark-backend-types.md new file mode 100644 index 000000000..d727690cc --- /dev/null +++ b/docs/snowpark/snowpark-backend-types.md @@ -0,0 +1,40 @@ +--- +id: snowpark-backend-types +title: Type mappings +--- + +# Type mappings + + When generating code using DataFrame operations types are mapped using the following criteria: + +| Elm/Morphir-IR type | Generated Scala type | Expected Snowflake type | +|-----------------------------------|--------------------------------|--------------------------------------------------------------------------------------------------------------------| +| `Int` | `Column`\* | [INT](https://docs.snowflake.com/en/sql-reference/data-types-numeric#int-integer-bigint-smallint-tinyint-byteint) | +| `Float` | `Column`\* | [DOUBLE](https://docs.snowflake.com/en/sql-reference/data-types-numeric#double-double-precision-real) | +| `Bool` | `Column`\* | [BOOLEAN](https://docs.snowflake.com/en/sql-reference/data-types-logical#boolean) | +| `String` | `Column`\* | [VARCHAR](https://docs.snowflake.com/en/sql-reference/data-types-text) | +| Custom types without parameters | `Column`\* | [VARCHAR](https://docs.snowflake.com/en/sql-reference/data-types-text) | +| Custom types with parameters | `Column`\* | [OBJECT](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#object) | +| Type alias | *As aliased* | *As aliased* | +| Record | Columns wrapper or **Column** | N/A | +| List of Record representing table | `DataFrame`\*\* | N/A | + +\* Snowpark [Column](https://docs.snowflake.com/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/Column.html). + +\*\* Snowpark [DataFrame](https://docs.snowflake.com/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/DataFrame.html). + + +When generating the code using Scala expressions the type conversion generates: + +| Elm/Morphir-IR type | Generated Scala type | +|-----------------------------------|--------------------------------| +| `Int` | `Int` | +| `Float` | `Double` | +| `Bool` | `Boolean` | +| `String` | `String` | +| Custom types without parameters | `String` | +| Custom types with parameters | **NOT IMPLEMENTED** | +| Type alias | *As aliased* | +| Record | Columns wrapper or **Column** | +| List of Record representing table | `DataFrame` | +| Complex Record | Scala case class | diff --git a/docs/snowpark/snowpark-backend-using-and-customize.md b/docs/snowpark/snowpark-backend-using-and-customize.md new file mode 100644 index 000000000..10772a222 --- /dev/null +++ b/docs/snowpark/snowpark-backend-using-and-customize.md @@ -0,0 +1,236 @@ +--- +id: snowpark-backend-using-and-customize +--- + +# Using the Snowpark backend and customizing the output + +## Using the backend + +The backend is selected by specifying `Snowpark` as the target. For example: + +```bash +$ morphir-elm gen -t Snowpark -o outputDir +``` + +## Identifying not supported cases + +The output directory where the Scala code was generated contains a file called `GenerationReport.md`. This is a markdown file which contains the following information: + +- Generation issues by function: Elements not converted listed by function +- Listing of functions generated using the DataFrame operations strategy +- Listing of functions generated using the Scala expressions strategy +- Listing of types identified as `DataFrames` + +An example of this report: + +```markdown +# Generation report + + +## Generation issues + + +### MyModel:Basic:getTasksEstimationInSeconds22 + +- Call to function not generated: Morphir.SDK:List:range + +## Functions generated using DataFrame operations strategy + +- `MyModel:Basic:addThreeNumbers` +- `MyModel:Basic:checkLastName` +- `MyModel:Basic:classifyDepartment` +- `MyModel:Basic:getEmployeeWithLastName` +- `MyModel:Basic:getEmployeesInList` +- `MyModel:Basic:getEmployeesWithLastName` +- `MyModel:Basic:toSpString` + +## Functions generated using Scala strategy + +- MyModel:Basic:avgSalaries + +## Types identified as DataFrames + +- MyModel:Basic:department +- MyModel:Basic:employee +``` + +### Customizing the output using decorations + +The Snowpark backend supports a way to apply two customizations using [Morphir decorations](https://morphir.finos.org/docs/decorations-users-guide) . + +Two customizations could be applied : "Inline function call" or "Cache result" . + +#### Inlining functions + +The **Inline element** decoration allows the user to inline a function definition. For example given the following code: + +```elm +toSpString : CardinalDirection -> String +toSpString direction = + case direction of + North -> + "Norte" + South -> + "Sur" + East -> + "Este" + West -> + "Oeste" + +spanishDirections : List Directions -> List { translation : String } +spanishDirections directions = + directions + |> List.map (\dir -> { translation = toSpString dir.direction }) +``` + +The generated code for these definitions is: + +```scala +def toSpString( + direction: com.snowflake.snowpark.Column +)( + implicit sfSession: com.snowflake.snowpark.Session +): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (direction) === (myModel.Basic.CardinalDirection.West), + com.snowflake.snowpark.functions.lit("Oeste") + ).when( + (direction) === (myModel.Basic.CardinalDirection.East), + com.snowflake.snowpark.functions.lit("Este") + ).when( + (direction) === (myModel.Basic.CardinalDirection.South), + com.snowflake.snowpark.functions.lit("Sur") + ).when( + (direction) === (myModel.Basic.CardinalDirection.North), + com.snowflake.snowpark.functions.lit("Norte") + ) + +def spanishDirections( + directions: com.snowflake.snowpark.DataFrame +)( + implicit sfSession: com.snowflake.snowpark.Session +): com.snowflake.snowpark.DataFrame = { + val directionsColumns: myModel.Basic.Directions = new myModel.Basic.DirectionsWrapper(directions) + + directions.select(myModel.Basic.toSpString(directionsColumns.direction).as("translation")) +} +``` + +By adding the `Inline element` decoration we can inline the `toSpString` function call inside `spanishDirections`. + +![inline decoration](sp_inline_decoration.png) + +Regenerating the code with these decorations shows that the definition was inlined in the place where the function was invoked. + +```scala + def spanishDirections( + directions: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val directionsColumns: myModel.Basic.Directions = new myModel.Basic.DirectionsWrapper(directions) + + directions.select(com.snowflake.snowpark.functions.when( + (directionsColumns.direction) === (myModel.Basic.CardinalDirection.West), + com.snowflake.snowpark.functions.lit("Oeste") + ).when( + (directionsColumns.direction) === (myModel.Basic.CardinalDirection.East), + com.snowflake.snowpark.functions.lit("Este") + ).when( + (directionsColumns.direction) === (myModel.Basic.CardinalDirection.South), + com.snowflake.snowpark.functions.lit("Sur") + ).when( + (directionsColumns.direction) === (myModel.Basic.CardinalDirection.North), + com.snowflake.snowpark.functions.lit("Norte") + ).as("translation")) + } +``` + +### Cache result + +Another customization allows the user to specify that caching code need to be generated for a specific function. + +For example given this function: + +```elm +getEmployeesWithLastName : String -> List Employee -> List Employee +getEmployeesWithLastName lastName employees = + employees + |> List.filter (\employee -> employee.lastName == lastName) +``` + +The code generated for this function looks like this: + +```scala + def getEmployeeWithLastName( + lastName: com.snowflake.snowpark.Column + )( + employees: com.snowflake.snowpark.DataFrame + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.DataFrame = { + val employeesColumns: myModel.Basic.Employee = new myModel.Basic.EmployeeWrapper(employees) + + employees.filter(myModel.Basic.checkLastName(lastName)(employeesColumns)) + } +``` + +We can add caching to this function with a decoration like this: + +![inline decoration](sp_caching_decoration.png) + +Regenerating the code show a different output. + +```scala +def getEmployeesWithLastName( + lastName: com.snowflake.snowpark.Column +)( + employees: com.snowflake.snowpark.DataFrame +)( + implicit sfSession: com.snowflake.snowpark.Session +): com.snowflake.snowpark.DataFrame = + getEmployeesWithLastNameCache.getOrElseUpdate( + (lastName, employees, sfSession), + { + val employeesColumns: myModel.Basic.Employee = new myModel.Basic.EmployeeWrapper(employees) + + employees.filter((employeesColumns.lastName) === (lastName)) + }.cacheResult + ) +``` + +Notice that this code use the [cacheResult](https://docs.snowflake.com/en/developer-guide/snowpark/scala/working-with-dataframes#caching-a-dataframe) mechanism. + +## Configuring the project for using Snowpark decorations + +Some modifications to the `morphir.json` are required to add these decorations. Here is an example of the configuration that needs to be added to this file: + +```json +{ + "name": "MyModel", + "sourceDirectory": "src", + "decorations": { + "snowparkgendecorations": { + "displayName" : "Snowpark generation customization", + "entryPoint": "SnowparkGenCustomization:Decorations:GenerationCustomization", + "ir": "out/decorations/morphir-ir.json", + "storageLocation": "spdecorations.json" + } + } +} +``` + +Every time code is generated with this Snowpark backend a `decorations` directory is created in the output directory. To generate `morphir-ir.json` file for the decorations model you need to run the `make` command in this directory: + +```bash +$ cd decorations +$ morphir-elm make +``` + +## Using decoration when generating code + +The `-dec` command line parameter is used to specify the decorations generated with the Morphir UI . For example given that the `spdecorations.json` name is used in the `storageLocation` section we can write: + +```bash +$ morphir-elm gen -t Snowpark -o output -dec spdecorations.json +``` diff --git a/docs/snowpark/snowpark-backend-value-mapping.md b/docs/snowpark/snowpark-backend-value-mapping.md new file mode 100644 index 000000000..ad3334a5a --- /dev/null +++ b/docs/snowpark/snowpark-backend-value-mapping.md @@ -0,0 +1,422 @@ +--- +id: snowpark-backend-value-mappings +title: Snowpark backend value mappings +--- + +# Value mappings for DataFrame operations + +This document contains a description of how different kinds of **Morphir-IR** elements are generated to Scala with the Snowpark API. + +## Literals + +*Source* + +```elm +10 +"Hello" +True +``` + +*Target* + +```Scala +com.snowflake.snowpark.functions.lit(10) +com.snowflake.snowpark.functions.lit("Hello") +com.snowflake.snowpark.functions.lit(true) +``` + +## Field access values + +Field access expressions like `a.b` are converted depending on the value that is being accessed. For example the following function contains an access to the `lastName` field of the `Employee` record: + +*Source* + +```elm +checkLastName : String -> Employee -> Bool +checkLastName name employee = + if employee.lastName == name then + True + else + False +``` + +*Target* + +```scala + def checkLastName( + name: com.snowflake.snowpark.Column + )( + employee: myModel.Basic.Employee + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (employee.lastName) === (name), + com.snowflake.snowpark.functions.lit(true) + ).otherwise(com.snowflake.snowpark.functions.lit(false)) +``` + +As presented above the `employee.lastName` expression in Elm was generated as `employee.lastName`. + +## Variable values + +Variable access like `myValue` are almost always converted to variable accesses in Scala. There are few exceptions like access to global elements where identifiers are generated fully qualified. + +## Constructor call values + +Constructor invocations are generated depending of the current strategy being used by the backend. Some cases include: + +### Custom type without parameters + +*Source* + +```elm +type CardinalDirection + = North + | South + | East + | West + +myFunc : CardinalDirection +myFunc = + let + direction = North + in + direction +``` + +*Target* + +```scala +object CardinalDirection{ + + def East: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("East") + + def North: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("North") + + def South: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("South") + + def West: com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.lit("West") + +} + +def myFunc: com.snowflake.snowpark.Column = { + val direction = myModel.Basic.CardinalDirection.North + + direction +} +``` + +Notice that the call to construct `North` was replaced by an access to the helper object `CardinalDirection` . + +### Custom type with parameters + +In this case the convention is use a JSON object to represent values. For example: + +*Source* + +```elm +type TimeRange = + Zero + | Seconds Int + | MinutesAndSeconds Int Int + +createMinutesAndSecs : Int -> Int -> TimeRange +createMinutesAndSecs min sec = + MinutesAndSeconds min sec +``` + +*Target* + +```scala + def createMinutesAndSecs( + min: com.snowflake.snowpark.Column + )( + sec: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.object_construct( + com.snowflake.snowpark.functions.lit("__tag"), + com.snowflake.snowpark.functions.lit("MinutesAndSeconds"), + com.snowflake.snowpark.functions.lit("field0"), + min, + com.snowflake.snowpark.functions.lit("field1"), + sec + ) +``` + +### Returning records from functions + +In the case that a function returns a record, an [array](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#array) is created to store the data. + +*Source* + +```elm +type alias EmpRes = + { code : Int + , name : String + } + +applyProcToEmployee : Employee -> Maybe EmpRes +applyProcToEmployee employee = + if employee.lastName == "Solo" then + Just <| EmpRes 1010 employee.firstName + else + Nothing +``` + +*Target* + +```scala + def applyProcToEmployee( + employee: myModel.Basic.Employee + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (employee.lastName) === (com.snowflake.snowpark.functions.lit("Solo")), + com.snowflake.snowpark.functions.array_construct( + com.snowflake.snowpark.functions.lit(1010), + employee.firstName + ) + ).otherwise(com.snowflake.snowpark.functions.lit(null)) +``` + +## List literal values + +Literal lists are converted a Scala [Seq](https://www.scala-lang.org/api/2.12.x/scala/collection/Seq.html) . + +*Source* + +```elm +someNames : List String +someNames = [ "Solo", "Jones" ] +``` + +*Target* + +```scala + def someNames: Seq[com.snowflake.snowpark.Column] = + Seq( + com.snowflake.snowpark.functions.lit("Solo"), + com.snowflake.snowpark.functions.lit("Jones") + ) +``` + +Sometimes that mapping function for an specific builtin function like `List.member` maybe change the conversion of literal lists. + +## Case/of values + +[Case/of](https://guide.elm-lang.org/types/pattern_matching) expressions are converted to a series of [when/otherwise](https://docs.snowflake.com/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/CaseExpr.html#when(condition:com.snowflake.snowpark.Column,value:com.snowflake.snowpark.Column):com.snowflake.snowpark.CaseExpr) expressions. + +*Source* + +```elm +type CardinalDirection + = North + | South + | East + | West + +toSpString : CardinalDirection -> String +toSpString direction = + case direction of + North -> + "Norte" + South -> + "Sur" + East -> + "Este" + West -> + "Oeste" +``` + +*Target* + +```scala + def toSpString( + direction: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (direction) === (myModel.Basic.CardinalDirection.West), + com.snowflake.snowpark.functions.lit("Oeste") + ).when( + (direction) === (myModel.Basic.CardinalDirection.East), + com.snowflake.snowpark.functions.lit("Este") + ).when( + (direction) === (myModel.Basic.CardinalDirection.South), + com.snowflake.snowpark.functions.lit("Sur") + ).when( + (direction) === (myModel.Basic.CardinalDirection.North), + com.snowflake.snowpark.functions.lit("Norte") + ) +``` + +## If/then/else values + +`If/then/else` expressions are converted to a series of [when/otherwise](https://docs.snowflake.com/developer-guide/snowpark/reference/scala/com/snowflake/snowpark/CaseExpr.html#when(condition:com.snowflake.snowpark.Column,value:com.snowflake.snowpark.Column):com.snowflake.snowpark.CaseExpr) expressions. + +*Source* + +```elm +if employee.lastName == name then + True +else + False +``` + +*Target* + +```scala + def checkLastName( + name: com.snowflake.snowpark.Column + )( + employee: myModel.Basic.Employee + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + com.snowflake.snowpark.functions.when( + (employee.lastName) === (name), + com.snowflake.snowpark.functions.lit(true) + ).otherwise(com.snowflake.snowpark.functions.lit(false)) +``` + +## Let definition values + +`Let` expressions are converted to a sequence of Scala `val` declarations: + +*Source* + +```elm +myFunc2: Int -> Int +myFunc2 x = + let + y = x + 1 + z = y + 1 + in + x + y + z +``` + +*Target* + +```scala + def myFunc2( + x: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = { + val y = (x) + (com.snowflake.snowpark.functions.lit(1)) + + val z = (y) + (com.snowflake.snowpark.functions.lit(1)) + + ((x) + (y)) + (z) + } +``` + +## Tuple values + +Tuples are treated as Snowflake [arrays](https://docs.snowflake.com/en/sql-reference/data-types-semistructured#array) . For example: + +*Source* + +```elm +let + y = x + 1 + z = y + 1 +in +(x, y, z) +``` + +*Target* + +```scala +{ + val y = (x) + (com.snowflake.snowpark.functions.lit(1)) + + val z = (y) + (com.snowflake.snowpark.functions.lit(1)) + + com.snowflake.snowpark.functions.array_construct( + x, + y, + z + ) +} +``` + +## Record values + +Record creation is generated depending of the context where the mapping occurs. + +For example, a sequence of arguments to `DataFrame.select` is created for a record is created as part of a `List.map` operation. + +```elm +trades + |> List.map + (\t -> + { product = t.productID + , qty = t.quantity + } + ) +``` + +This generates: + +```scala +trades.select( + tradesColumns.productID.as("product"), + tradesColumns.quantity.as("qty") +) +``` + +## User defined function invocation values + +User defined functions are generated as Scala methods . This backend define the functions using [multiple parameter lists](https://docs.scala-lang.org/tour/multiple-parameter-lists.html) . + +```elm +aValue = addThreeNumbers 10 20 30 + +addThreeNumbers : Int -> Int -> Int -> Int +addThreeNumbers x y z = + x + y + z + +addTwo : Int -> Int -> Int +addTwo = addThreeNumbers 2 +``` + +*Target* + +```scala + def aValue: TypeNotConverted = + myModel.Basic.addThreeNumbers(com.snowflake.snowpark.functions.lit(10))(com.snowflake.snowpark.functions.lit(20))(com.snowflake.snowpark.functions.lit(30)) + + def addThreeNumbers( + x: com.snowflake.snowpark.Column + )( + y: com.snowflake.snowpark.Column + )( + z: com.snowflake.snowpark.Column + )( + implicit sfSession: com.snowflake.snowpark.Session + ): com.snowflake.snowpark.Column = + ((x) + (y)) + (z) + + def addTwo: com.snowflake.snowpark.Column => com.snowflake.snowpark.Column => com.snowflake.snowpark.Column = + myModel.Basic.addThreeNumbers(com.snowflake.snowpark.functions.lit(2)) +``` + +## Builtin function invocation values + +Builtin functions are converted using different strategies depending on each case. The following document contains a description of this case. + +# Value mappings for plain Scala operations + +Although few operations are supported, there are support for converting functions classified as "complex" (functions that receive or return non-Dataframe compatible values). + + diff --git a/docs/snowpark/snowpark-backend.svg b/docs/snowpark/snowpark-backend.svg new file mode 100644 index 000000000..2df579892 --- /dev/null +++ b/docs/snowpark/snowpark-backend.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/snowpark/sp_caching_decoration.png b/docs/snowpark/sp_caching_decoration.png new file mode 100644 index 000000000..d197a069e Binary files /dev/null and b/docs/snowpark/sp_caching_decoration.png differ diff --git a/docs/snowpark/sp_inline_decoration.png b/docs/snowpark/sp_inline_decoration.png new file mode 100644 index 000000000..6043f6e68 Binary files /dev/null and b/docs/snowpark/sp_inline_decoration.png differ diff --git a/docs/snowpark/sp_jupyter_nb.png b/docs/snowpark/sp_jupyter_nb.png new file mode 100644 index 000000000..0d125fd24 Binary files /dev/null and b/docs/snowpark/sp_jupyter_nb.png differ diff --git a/elm-tooling.json b/elm-tooling.json new file mode 100644 index 000000000..e4c63d5bf --- /dev/null +++ b/elm-tooling.json @@ -0,0 +1,7 @@ +{ + "tools": { + "elm": "0.19.1", + "elm-format": "0.8.5", + "elm-json": "0.2.13" + } +} diff --git a/elm.json b/elm.json index 08d5732fc..f289bf111 100644 --- a/elm.json +++ b/elm.json @@ -3,14 +3,13 @@ "name": "finos/morphir-elm", "summary": "Morphir Elm bindings", "license": "Apache-2.0", - "version": "20.0.0", + "version": "21.0.1", "exposed-modules": [ "Morphir.SDK.Decimal", "Morphir.SDK.Int", "Morphir.SDK.String", "Morphir.SDK.List", "Morphir.SDK.LocalDate", - "Morphir.SDK.Month", "Morphir.SDK.Number", "Morphir.SDK.Rule", "Morphir.SDK.Key", @@ -20,6 +19,9 @@ "Morphir.SDK.ResultList", "Morphir.SDK.LocalTime", "Morphir.IR.Name", + "Morphir.IR.NodeId", + "Morphir.IR.Decoration", + "Morphir.IR.Decoration.Codec", "Morphir.IR.Path", "Morphir.IR.QName", "Morphir.IR.FQName", @@ -75,6 +77,7 @@ "fabhof/elm-ui-datepicker": "5.0.0 <= v < 6.0.0", "justinmimbs/date": "3.2.1 <= v < 4.0.0", "lattyware/elm-fontawesome": "6.0.0 <= v < 7.0.0", + "matthewsj/elm-ordering": "2.0.0 <= v < 3.0.0", "mdgriffith/elm-ui": "1.1.8 <= v < 2.0.0", "pzp1997/assoc-list": "1.0.0 <= v < 2.0.0", "rtfeldman/elm-iso8601-date-strings": "1.1.4 <= v < 2.0.0", diff --git a/gulpfile.js b/gulpfile.js index 2b7dbb180..cec88f144 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -18,7 +18,7 @@ const cliTsProject = ts.createProject('./cli2/tsconfig.json') const readFile = util.promisify(fs.readFile) const config = { - morphirJvmVersion: '0.13.0', + morphirJvmVersion: '0.18.2', morphirJvmCloneDir: tmp.dirSync() } @@ -99,6 +99,7 @@ const buildMorphirAPI2 = async ()=>{ .pipe(dest('./lib/generated/morphir/sdk')) return await execa('npx tsc', ['--project',path.join('.','lib','tsconfig.json')]) } catch (error) { + console.error("Error building morphir API 2", error); return error } @@ -168,6 +169,7 @@ async function morphirJsonSchemaGen(inputPath, outputDir, target) { try { await execa('node', args, {stdio}) } catch (err) { + console.log("Error running json-schema-gen command", err); throw(err) } } @@ -295,7 +297,7 @@ async function testIntegrationBuildSpark(cb) { ) } catch (err) { if (err.code == 'ENOENT') { - console.log("Skipping testIntegrationBuildSpark as `mill` build tool isn't available."); + console.error("Skipping testIntegrationBuildSpark as `mill` build tool isn't available."); } else { throw err; } @@ -310,7 +312,7 @@ async function testIntegrationTestSpark(cb) { ) } catch (err) { if (err.code == 'ENOENT') { - console.log("Skipping testIntegrationTestSpark as `mill` build tool isn't available."); + console.error("Skipping testIntegrationTestSpark as `mill` build tool isn't available."); } else { throw err; } @@ -339,7 +341,7 @@ async function testCreateCSV(cb) { } else { code_no = shell.exec('bash ./create_csv_files.sh', { cwd: './tests-integration/spark/elm-tests/tests' }).code if (code_no != 0) { - console.log('ERROR: CSV files cannot be created') + console.error('ERROR: CSV files cannot be created') return false; } } diff --git a/lib/main.ts b/lib/main.ts index 351616e7a..94549abdb 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -1,5 +1,3 @@ -import * as fs from "fs"; -import * as util from "util"; import { Morphir_IR_Distribution as Distribution } from "./generated/morphir/ir/Distribution"; import { Morphir_IR_Module } from "./generated/morphir/ir/Module"; import { Morphir_IR_Package } from "./generated/morphir/ir/Package"; @@ -7,28 +5,6 @@ import { Morphir_IR_Path } from "./generated/morphir/ir/Path"; import { Morphir_IR_Type } from "./generated/morphir/ir/Type"; import { Morphir } from "./generated/Morphir"; -const fsReadFile = util.promisify(fs.readFile); - -fsReadFile("./morphir-ir.json") - .then((content) => { - const ir: Distribution.Distribution = toDistribution(content.toString()); - switch (ir.kind) { - case "Library": - ir.arg3.modules.forEach((accessControlledModuleDef, moduleName) => { - console.log( - moduleName.map((n) => n.map(capitalize).join("")).join(".") - ); - accessControlledModuleDef.value.types.forEach( - (documentedAccessControlledTypeDef, typeName) => { - console.log(` - ${typeName}`); - } - ); - }); - } - }) - .catch((error) => { - console.error(error); - }); function toDistribution(text: string): Distribution.Distribution { let data = JSON.parse(text); diff --git a/morphir-decoration-extension/package-lock.json b/morphir-decoration-extension/package-lock.json index 215009a5a..13965c941 100644 --- a/morphir-decoration-extension/package-lock.json +++ b/morphir-decoration-extension/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "comment-json": "^4.2.3", "jsonc-parser": "^3.2.0", - "morphir-elm": "^2.80.0" + "morphir-elm": "^2.86.0" }, "devDependencies": { "@types/glob": "^8.1.0", @@ -35,102 +35,6 @@ "vscode": "^1.76.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -275,18 +179,11 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/@morphir/typespec-sdk": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@morphir/typespec-sdk/-/typespec-sdk-0.1.0.tgz", - "integrity": "sha512-x6qCqOA4Sh+Wj7IV4bxz0R5jtMzlCbUHdq2UYS49I1UWCdKD155WMzfitb+950aeupMskzfJDziiXkrtVEKEhw==", - "dependencies": { - "@typespec/compiler": "latest" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -299,6 +196,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } @@ -307,6 +205,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -596,136 +495,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typespec/compiler": { - "version": "0.44.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.44.0.tgz", - "integrity": "sha512-NESRujXwHHhJZsHn+Bf4zOlJ2eTJB/oYRIFMqV7lAOut3OILngQfmO3iVLpTVrHjwgrUdetU1GXt1Ref3rmATA==", - "dependencies": { - "@babel/code-frame": "~7.21.4", - "ajv": "~8.12.0", - "change-case": "~4.1.2", - "globby": "~13.1.1", - "js-yaml": "~4.1.0", - "mkdirp": "~2.1.6", - "mustache": "~4.2.0", - "node-fetch": "3.2.8", - "node-watch": "~0.7.1", - "picocolors": "~1.0.0", - "prettier": "~2.8.7", - "prompts": "~2.4.1", - "vscode-languageserver": "~8.1.0", - "vscode-languageserver-textdocument": "~1.0.1", - "yargs": "~17.7.1" - }, - "bin": { - "tsp": "cmd/tsp.js", - "tsp-server": "cmd/tsp-server.js" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@typespec/compiler/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@typespec/compiler/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@typespec/compiler/node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typespec/compiler/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/@typespec/compiler/node_modules/mkdirp": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", - "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typespec/compiler/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typespec/compiler/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@typespec/compiler/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, "node_modules/@vscode/test-electron": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.0.tgz", @@ -1067,6 +836,31 @@ "node": ">=6" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1105,7 +899,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-flatten": { "version": "1.1.1", @@ -1140,6 +935,25 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1149,6 +963,29 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -1213,6 +1050,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -1254,6 +1092,29 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -1298,20 +1159,6 @@ "node": ">=6" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camel-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -1340,21 +1187,6 @@ } ] }, - "node_modules/capital-case": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", - "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" - } - }, - "node_modules/capital-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1370,29 +1202,10 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/change-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", - "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", - "dependencies": { - "camel-case": "^4.1.2", - "capital-case": "^1.0.4", - "constant-case": "^3.0.4", - "dot-case": "^3.0.4", - "header-case": "^2.0.4", - "no-case": "^3.0.4", - "param-case": "^3.0.4", - "pascal-case": "^3.1.2", - "path-case": "^3.0.4", - "sentence-case": "^3.0.4", - "snake-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/change-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "node_modules/chokidar": { "version": "3.5.3", @@ -1442,6 +1255,36 @@ "node": ">=6.0" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -1453,6 +1296,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1605,21 +1456,6 @@ "node": ">=12" } }, - "node_modules/constant-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", - "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case": "^2.0.2" - } - }, - "node_modules/constant-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1702,14 +1538,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/date-fns": { "version": "2.29.3", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", @@ -1758,6 +1586,17 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1797,6 +1636,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -1816,20 +1656,6 @@ "node": ">=6.0.0" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dot-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1895,6 +1721,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } @@ -2245,6 +2072,19 @@ } ] }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2254,6 +2094,7 @@ "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -2269,6 +2110,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -2301,30 +2143,31 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } }, - "node_modules/fetch-blob": { + "node_modules/figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" } }, "node_modules/file-entry-cache": { @@ -2343,6 +2186,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2424,17 +2268,6 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2494,6 +2327,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2673,20 +2507,6 @@ "he": "bin/he" } }, - "node_modules/header-case": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", - "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", - "dependencies": { - "capital-case": "^1.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/header-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -2740,10 +2560,30 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, "engines": { "node": ">= 4" } @@ -2813,6 +2653,44 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/interpret": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", @@ -2858,6 +2736,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -2874,6 +2753,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -2881,10 +2761,19 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } @@ -2923,7 +2812,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, "engines": { "node": ">=10" }, @@ -2991,15 +2879,11 @@ "url": "https://opencollective.com/js-sdsl" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -3068,14 +2952,6 @@ "node": ">=0.10.0" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3125,8 +3001,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -3146,7 +3021,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -3169,19 +3043,6 @@ "node": "*" } }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lower-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3229,6 +3090,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "engines": { "node": ">= 8" } @@ -3245,6 +3107,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -3283,6 +3146,14 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -3440,19 +3311,19 @@ } }, "node_modules/morphir-elm": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/morphir-elm/-/morphir-elm-2.80.0.tgz", - "integrity": "sha512-d9y61AMDQvRM7k4vMh4UvnWd/4qiTVzJoKvBaGURviB3NlEovhzqxKsYeA+sPTyAvMLqMuNS73qFlXXHPD+wdw==", + "version": "2.86.0", + "resolved": "https://registry.npmjs.org/morphir-elm/-/morphir-elm-2.86.0.tgz", + "integrity": "sha512-6qWxSzQa6hw6GUOFLvTQDYwOuTE0T+WmB37ohDXCGRVKi+1kdV6+NXQaCOKI6kGEQJfAOAvOG0X73P+iw1f0+A==", "dependencies": { - "@morphir/typespec-sdk": "^0.1.0", "ajv": "^8.10.0", "ajv-formats": "^2.1.1", "chalk": "^4.1.1", "commander": "^9.0.0", "cookie-parser": "^1.4.6", - "express": "^4.17.3", + "express": "^4.18.2", "fs-extra": "^9.1.0", "get-stdin": "^8.0.0", + "inquirer": "^8.0.0", "log-timestamp": "^0.3.0", "prettier": "^2.4.1", "vis-network": "^9.1.2" @@ -3461,6 +3332,10 @@ "morphir": "cli2/lib/morphir.js", "morphir-dapr": "cli/morphir-dapr.js", "morphir-elm": "cli/morphir-elm.js" + }, + "engines": { + "node": "*", + "npm": "*" } }, "node_modules/morphir-elm/node_modules/ajv": { @@ -3506,13 +3381,10 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "bin": { - "mustache": "bin/mustache" - } + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/nanoid": { "version": "3.3.3", @@ -3540,81 +3412,24 @@ }, "node_modules/negotiator": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/no-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.8.tgz", - "integrity": "sha512-KtpD1YhGszhntMpBDyp5lyagk8KIMopC1LEb7cQUAh7zcosaX5uK8HnbNb2i3NTQK3sIawCItS0uFC3QzcLHdg==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "node_modules/node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, - "node_modules/node-watch": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", - "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3652,6 +3467,20 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3669,6 +3498,36 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3714,20 +3573,6 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/param-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3748,34 +3593,6 @@ "node": ">= 0.8" } }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/pascal-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/path-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", - "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3818,6 +3635,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "engines": { "node": ">=8" } @@ -3825,12 +3643,14 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -3912,9 +3732,9 @@ } }, "node_modules/prettier": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "bin": { "prettier": "bin-prettier.js" }, @@ -3931,18 +3751,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3967,6 +3775,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -4076,6 +3885,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -4135,10 +3945,23 @@ "node": ">=4" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4179,10 +4002,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -4205,7 +4037,6 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, "dependencies": { "tslib": "^2.1.0" } @@ -4213,8 +4044,7 @@ "node_modules/rxjs/node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" }, "node_modules/sade": { "version": "1.8.1", @@ -4231,8 +4061,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -4357,21 +4186,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/sentence-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", - "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" - } - }, - "node_modules/sentence-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -4461,10 +4275,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/slash": { "version": "3.0.0", @@ -4475,20 +4289,6 @@ "node": ">=8" } }, - "node_modules/snake-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/snake-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/sorcery": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", @@ -4541,7 +4341,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -4787,16 +4586,33 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, "node_modules/timsort": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", "peer": true }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -4952,32 +4768,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/upper-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", - "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/upper-case-first": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", - "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/upper-case-first/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/upper-case/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -4989,8 +4779,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", @@ -5068,44 +4857,6 @@ "component-emitter": "^1.3.0" } }, - "node_modules/vscode-jsonrpc": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", - "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.1.0.tgz", - "integrity": "sha512-eUt8f1z2N2IEUDBsKaNapkz7jl5QpskN2Y0G01T/ItMxBxw1fJwvtySGB9QMecatne8jFIWJGWI61dWjyTLQsw==", - "dependencies": { - "vscode-languageserver-protocol": "3.17.3" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz", - "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==", - "dependencies": { - "vscode-jsonrpc": "8.1.0", - "vscode-languageserver-types": "3.17.3" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", - "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==" - }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -5119,12 +4870,12 @@ "node": ">=10.13.0" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" } }, "node_modules/webpack": { @@ -5272,9 +5023,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5290,6 +5041,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5312,6 +5064,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "engines": { "node": ">=10" } @@ -5378,80 +5131,6 @@ } }, "dependencies": { - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -5562,18 +5241,11 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "@morphir/typespec-sdk": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@morphir/typespec-sdk/-/typespec-sdk-0.1.0.tgz", - "integrity": "sha512-x6qCqOA4Sh+Wj7IV4bxz0R5jtMzlCbUHdq2UYS49I1UWCdKD155WMzfitb+950aeupMskzfJDziiXkrtVEKEhw==", - "requires": { - "@typespec/compiler": "latest" - } - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -5582,12 +5254,14 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -5782,97 +5456,6 @@ "eslint-visitor-keys": "^3.3.0" } }, - "@typespec/compiler": { - "version": "0.44.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.44.0.tgz", - "integrity": "sha512-NESRujXwHHhJZsHn+Bf4zOlJ2eTJB/oYRIFMqV7lAOut3OILngQfmO3iVLpTVrHjwgrUdetU1GXt1Ref3rmATA==", - "requires": { - "@babel/code-frame": "~7.21.4", - "ajv": "~8.12.0", - "change-case": "~4.1.2", - "globby": "~13.1.1", - "js-yaml": "~4.1.0", - "mkdirp": "~2.1.6", - "mustache": "~4.2.0", - "node-fetch": "3.2.8", - "node-watch": "~0.7.1", - "picocolors": "~1.0.0", - "prettier": "~2.8.7", - "prompts": "~2.4.1", - "vscode-languageserver": "~8.1.0", - "vscode-languageserver-textdocument": "~1.0.1", - "yargs": "~17.7.1" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "mkdirp": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", - "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==" - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" - }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" - } - } - }, "@vscode/test-electron": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.0.tgz", @@ -6153,6 +5736,21 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6179,7 +5777,8 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-flatten": { "version": "1.1.1", @@ -6208,12 +5807,39 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -6270,6 +5896,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -6292,6 +5919,15 @@ "update-browserslist-db": "^1.0.10" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -6321,24 +5957,8 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, "camelcase": { "version": "6.3.0", @@ -6352,23 +5972,6 @@ "integrity": "sha512-oww27MtUmusatpRpCGSOneQk2/l5czXANDSFvsc7VuOQ86s3ANhZetpwXNf1zY/zdfP63Xvjz325DAdAoES13g==", "dev": true }, - "capital-case": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", - "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6378,31 +5981,10 @@ "supports-color": "^7.1.0" } }, - "change-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", - "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", - "requires": { - "camel-case": "^4.1.2", - "capital-case": "^1.0.4", - "constant-case": "^3.0.4", - "dot-case": "^3.0.4", - "header-case": "^2.0.4", - "no-case": "^3.0.4", - "param-case": "^3.0.4", - "pascal-case": "^3.1.2", - "path-case": "^3.0.4", - "sentence-case": "^3.0.4", - "snake-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "chokidar": { "version": "3.5.3", @@ -6437,6 +6019,24 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==" + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -6448,6 +6048,11 @@ "wrap-ansi": "^7.0.0" } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -6568,23 +6173,6 @@ } } }, - "constant-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", - "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case": "^2.0.2" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -6640,11 +6228,6 @@ "which": "^2.0.1" } }, - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" - }, "date-fns": { "version": "2.29.3", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", @@ -6672,6 +6255,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "requires": { + "clone": "^1.0.2" + } + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -6698,6 +6289,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "requires": { "path-type": "^4.0.0" } @@ -6711,22 +6303,6 @@ "esutils": "^2.0.2" } }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -6779,7 +6355,8 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, "escape-html": { "version": "1.0.3", @@ -7035,6 +6612,16 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7044,6 +6631,7 @@ "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -7056,6 +6644,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -7084,17 +6673,24 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, "requires": { "reusify": "^1.0.4" } }, - "fetch-blob": { + "figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + } } }, "file-entry-cache": { @@ -7110,6 +6706,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -7175,14 +6772,6 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" - } - }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -7225,7 +6814,8 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "get-intrinsic": { "version": "1.2.0", @@ -7353,22 +6943,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "header-case": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", - "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", - "requires": { - "capital-case": "^1.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -7410,10 +6984,16 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true }, "immediate": { "version": "3.0.6", @@ -7462,6 +7042,40 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "dependencies": { + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, "interpret": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", @@ -7494,7 +7108,8 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -7505,14 +7120,21 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-path-inside": { "version": "3.0.3", @@ -7538,8 +7160,7 @@ "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" }, "isarray": { "version": "1.0.0", @@ -7587,15 +7208,11 @@ "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", "dev": true }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { "argparse": "^2.0.1" } @@ -7656,11 +7273,6 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -7698,8 +7310,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.merge": { "version": "4.6.2", @@ -7716,7 +7327,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, "requires": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -7730,21 +7340,6 @@ "log-prefix": "0.1.1" } }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "requires": { - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7782,7 +7377,8 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true }, "methods": { "version": "1.1.2", @@ -7793,6 +7389,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "requires": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -7816,6 +7413,11 @@ "mime-db": "1.52.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -7938,19 +7540,19 @@ } }, "morphir-elm": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/morphir-elm/-/morphir-elm-2.80.0.tgz", - "integrity": "sha512-d9y61AMDQvRM7k4vMh4UvnWd/4qiTVzJoKvBaGURviB3NlEovhzqxKsYeA+sPTyAvMLqMuNS73qFlXXHPD+wdw==", + "version": "2.86.0", + "resolved": "https://registry.npmjs.org/morphir-elm/-/morphir-elm-2.86.0.tgz", + "integrity": "sha512-6qWxSzQa6hw6GUOFLvTQDYwOuTE0T+WmB37ohDXCGRVKi+1kdV6+NXQaCOKI6kGEQJfAOAvOG0X73P+iw1f0+A==", "requires": { - "@morphir/typespec-sdk": "^0.1.0", "ajv": "^8.10.0", "ajv-formats": "^2.1.1", "chalk": "^4.1.1", "commander": "^9.0.0", "cookie-parser": "^1.4.6", - "express": "^4.17.3", + "express": "^4.18.2", "fs-extra": "^9.1.0", "get-stdin": "^8.0.0", + "inquirer": "^8.0.0", "log-timestamp": "^0.3.0", "prettier": "^2.4.1", "vis-network": "^9.1.2" @@ -7991,10 +7593,10 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "nanoid": { "version": "3.3.3", @@ -8025,48 +7627,12 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.8.tgz", - "integrity": "sha512-KtpD1YhGszhntMpBDyp5lyagk8KIMopC1LEb7cQUAh7zcosaX5uK8HnbNb2i3NTQK3sIawCItS0uFC3QzcLHdg==", - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, "node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, - "node-watch": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", - "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==" - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -8095,6 +7661,14 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -8109,6 +7683,27 @@ "word-wrap": "^1.2.3" } }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8139,22 +7734,6 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8169,38 +7748,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, - "path-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", - "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -8233,17 +7780,20 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true }, "pkg-dir": { "version": "4.2.0", @@ -8300,9 +7850,9 @@ "dev": true }, "prettier": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==" + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==" }, "process-nextick-args": { "version": "2.0.1", @@ -8310,15 +7860,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8336,7 +7877,8 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true }, "randombytes": { "version": "2.1.0", @@ -8410,7 +7952,8 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true }, "require-from-string": { "version": "2.0.2", @@ -8451,10 +7994,20 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true }, "rimraf": { "version": "3.0.2", @@ -8481,10 +8034,16 @@ } } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "requires": { "queue-microtask": "^1.2.2" } @@ -8493,7 +8052,6 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, "requires": { "tslib": "^2.1.0" }, @@ -8501,8 +8059,7 @@ "tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" } } }, @@ -8518,8 +8075,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -8625,23 +8181,6 @@ } } }, - "sentence-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", - "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3", - "upper-case-first": "^2.0.2" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -8713,10 +8252,10 @@ "object-inspect": "^1.9.0" } }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "slash": { "version": "3.0.0", @@ -8724,22 +8263,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "snake-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", - "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "sorcery": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", @@ -8783,7 +8306,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -8919,16 +8441,30 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, "timsort": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", "peer": true }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -9021,36 +8557,6 @@ "picocolors": "^1.0.0" } }, - "upper-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", - "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", - "requires": { - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, - "upper-case-first": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", - "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", - "requires": { - "tslib": "^2.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - } - } - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -9062,8 +8568,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utils-merge": { "version": "1.0.1", @@ -9101,38 +8606,6 @@ "peer": true, "requires": {} }, - "vscode-jsonrpc": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", - "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==" - }, - "vscode-languageserver": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.1.0.tgz", - "integrity": "sha512-eUt8f1z2N2IEUDBsKaNapkz7jl5QpskN2Y0G01T/ItMxBxw1fJwvtySGB9QMecatne8jFIWJGWI61dWjyTLQsw==", - "requires": { - "vscode-languageserver-protocol": "3.17.3" - } - }, - "vscode-languageserver-protocol": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz", - "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==", - "requires": { - "vscode-jsonrpc": "8.1.0", - "vscode-languageserver-types": "3.17.3" - } - }, - "vscode-languageserver-textdocument": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" - }, - "vscode-languageserver-types": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", - "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==" - }, "watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -9143,10 +8616,13 @@ "graceful-fs": "^4.1.2" } }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } }, "webpack": { "version": "5.76.0", @@ -9241,9 +8717,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "workerpool": { @@ -9256,6 +8732,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9271,7 +8748,8 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true }, "yallist": { "version": "4.0.0", diff --git a/morphir-decoration-extension/package.json b/morphir-decoration-extension/package.json index 125aa6ab3..2e3467a2d 100644 --- a/morphir-decoration-extension/package.json +++ b/morphir-decoration-extension/package.json @@ -98,6 +98,6 @@ "dependencies": { "comment-json": "^4.2.3", "jsonc-parser": "^3.2.0", - "morphir-elm": "^2.80.0" + "morphir-elm": "^2.86.0" } } diff --git a/package-lock.json b/package-lock.json index 7b996d596..56da6e21a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,14 @@ { "name": "morphir-elm", - "version": "2.81.0", + "version": "2.87.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "morphir-elm", - "version": "2.81.0", + "version": "2.87.6", "license": "Apache-2.0", "dependencies": { - "@morphir/typespec-sdk": "^0.1.0", "ajv": "^8.10.0", "ajv-formats": "^2.1.1", "chalk": "^4.1.1", @@ -18,6 +17,7 @@ "express": "^4.18.2", "fs-extra": "^9.1.0", "get-stdin": "^8.0.0", + "inquirer": "^8.0.0", "log-timestamp": "^0.3.0", "prettier": "^2.4.1", "vis-network": "^9.1.2" @@ -28,15 +28,18 @@ "morphir-elm": "cli/morphir-elm.js" }, "devDependencies": { + "@morphir/typespec-sdk": "file:redistributable/TypeSpec/sdk", + "@types/inquirer": "^9.0.3", "@types/jest": "^27.4.0", "@types/mocha": "^9.0.0", "@typespec/compiler": "^0.42.0", - "@vercel/ncc": "^0.24.1", + "@vercel/ncc": "^0.38.1", "del-cli": "3.0.1", "elm": "^0.19.1-5", "elm-doc-preview": "^5.0.5", "elm-format": "^0.8.5", "elm-test": "^0.19.1-revision6", + "elm-tooling": "^1.15.0", "execa": "^5.1.1", "gulp": "^4.0.2", "gulp-mocha": "^8.0.0", @@ -51,6 +54,10 @@ "ts-jest": "^27.1.3", "ts-node": "^10.3.0", "typescript": "^4.4.3" + }, + "engines": { + "node": "*", + "npm": "*" } }, "node_modules/@ampproject/remapping": { @@ -65,10 +72,76 @@ "node": ">=6.0.0" } }, + "node_modules/@avh4/elm-format-darwin-arm64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-darwin-arm64/-/elm-format-darwin-arm64-0.8.7-2.tgz", + "integrity": "sha512-F5JD44mJ3KX960J5GkXMfh1/dtkXuPcQpX2EToHQKjLTZUfnhZ++ytQQt0gAvrJ0bzoOvhNzjNjUHDA1ruTVbg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@avh4/elm-format-darwin-x64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-darwin-x64/-/elm-format-darwin-x64-0.8.7-2.tgz", + "integrity": "sha512-4pfF1cl0KyTion+7Mg4XKM3yi4Yc7vP76Kt/DotLVGJOSag4ISGic1og2mt8RZZ7XArybBmHNyYkiUbe/cEiCw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@avh4/elm-format-linux-arm64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-linux-arm64/-/elm-format-linux-arm64-0.8.7-2.tgz", + "integrity": "sha512-WkVmuce2zU6s9dupHhqPc886Vaqpea8dZlxv2fpZ4wSzPUbiiKHoHZzoVndMIMTUL0TZukP3Ps0n/lWO5R5+FA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@avh4/elm-format-linux-x64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-linux-x64/-/elm-format-linux-x64-0.8.7-2.tgz", + "integrity": "sha512-kmncfJrTBjVT94JtQvMf4M5Pn2Yl0sZt3wo7AzgFiDnB/CiZ+KjJyXuWM64NeGiv4MQqzPq65tsFXUH1CIJeiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@avh4/elm-format-win32-x64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-win32-x64/-/elm-format-win32-x64-0.8.7-2.tgz", + "integrity": "sha512-sBdMBGq/8mD8Y5C+fIr5vlb3N50yB7S1MfgeAq2QEbvkr/sKrCZI540i43lZDH9gWsfA1w2W8wCe0penFYzsGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -139,23 +212,24 @@ "dev": true }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" @@ -180,59 +254,43 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -291,21 +349,31 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, "engines": { "node": ">=6.9.0" } @@ -334,12 +402,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -350,6 +419,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -361,6 +431,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -374,6 +445,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -381,12 +453,14 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "engines": { "node": ">=4" } @@ -395,6 +469,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -403,9 +478,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -577,33 +652,108 @@ } }, "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/template/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/template/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/template/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/template/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/template/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -611,6 +761,60 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/traverse/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, "node_modules/@babel/traverse/node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -628,19 +832,41 @@ } } }, + "node_modules/@babel/traverse/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/traverse/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@babel/traverse/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -686,6 +912,58 @@ "node": ">=0.8.0" } }, + "node_modules/@elm_binaries/darwin_arm64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/darwin_arm64/-/darwin_arm64-0.19.1-0.tgz", + "integrity": "sha512-mjbsH7BNHEAmoE2SCJFcfk5fIHwFIpxtSgnEAqMsVLpBUFoEtAeX+LQ+N0vSFJB3WAh73+QYx/xSluxxLcL6dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@elm_binaries/darwin_x64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/darwin_x64/-/darwin_x64-0.19.1-0.tgz", + "integrity": "sha512-QGUtrZTPBzaxgi9al6nr+9313wrnUVHuijzUK39UsPS+pa+n6CmWyV/69sHZeX9qy6UfeugE0PzF3qcUiy2GDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@elm_binaries/linux_x64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/linux_x64/-/linux_x64-0.19.1-0.tgz", + "integrity": "sha512-T1ZrWVhg2kKAsi8caOd3vp/1A3e21VuCpSG63x8rDie50fHbCytTway9B8WHEdnBFv4mYWiA68dzGxYCiFmU2w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@elm_binaries/win32_x64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/win32_x64/-/win32_x64-0.19.1-0.tgz", + "integrity": "sha512-yDleiXqSE9EcqKtd9SkC/4RIW8I71YsXzMPL79ub2bBPHjWTcoyyeBbYjoOB9SxSlArJ74HaoBApzT6hY7Zobg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1040,43 +1318,63 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz", - "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz", - "integrity": "sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@morphir/typespec-sdk": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@morphir/typespec-sdk/-/typespec-sdk-0.1.0.tgz", - "integrity": "sha512-x6qCqOA4Sh+Wj7IV4bxz0R5jtMzlCbUHdq2UYS49I1UWCdKD155WMzfitb+950aeupMskzfJDziiXkrtVEKEhw==", - "dependencies": { - "@typespec/compiler": "latest" - } + "resolved": "redistributable/TypeSpec/sdk", + "link": true }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" @@ -1089,6 +1387,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true, "engines": { "node": ">= 8" } @@ -1097,6 +1396,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" @@ -1243,6 +1543,16 @@ "integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==", "peer": true }, + "node_modules/@types/inquirer": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.3.tgz", + "integrity": "sha512-CzNkWqQftcmk2jaCWdBTf9Sm7xSw4rkI1zpU/Udw3HX5//adEZUIm9STtoRP1qgWj0CWQtJ9UTvqmO2NNjhMJw==", + "dev": true, + "dependencies": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -1319,6 +1629,15 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/through": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", + "integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -1338,6 +1657,7 @@ "version": "0.42.0", "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.42.0.tgz", "integrity": "sha512-eONMtlDQ5Bpge4lcprI06mnfW924bo23LVNNKTdC1/1g1iQWPGH2fNpstEomumzOvTNwINh3xKtwkJ5huckBUQ==", + "dev": true, "dependencies": { "@babel/code-frame": "~7.18.6", "ajv": "~8.11.2", @@ -1367,6 +1687,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -1375,6 +1696,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1388,6 +1710,7 @@ "version": "13.1.3", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", @@ -1406,6 +1729,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -1414,6 +1738,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -1425,6 +1750,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -1436,6 +1762,7 @@ "version": "2.8.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "dev": true, "bin": { "prettier": "bin-prettier.js" }, @@ -1450,6 +1777,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, "engines": { "node": ">=12" }, @@ -1461,6 +1789,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1474,6 +1803,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1485,6 +1815,7 @@ "version": "17.6.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -1502,6 +1833,7 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, "engines": { "node": ">=12" } @@ -1513,9 +1845,9 @@ "dev": true }, "node_modules/@vercel/ncc": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.24.1.tgz", - "integrity": "sha512-r9m7brz2hNmq5TF3sxrK4qR/FhXn44XIMglQUir4sT7Sh5GOaYXlMYikHFwJStf8rmQGTlvOoBXt4yHVonRG8A==", + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz", + "integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==", "dev": true, "bin": { "ncc": "dist/ncc/cli.js" @@ -1686,7 +2018,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -1701,7 +2032,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "engines": { "node": ">=10" }, @@ -1793,7 +2123,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/arr-diff": { "version": "4.0.0", @@ -1962,24 +2293,6 @@ "node": ">=0.10.0" } }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -2060,21 +2373,6 @@ "node": ">= 4.5.0" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "node_modules/babel-jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", @@ -2267,28 +2565,6 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dev": true, - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2308,22 +2584,6 @@ "file-uri-to-path": "1.0.0" } }, - "node_modules/binwrap": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/binwrap/-/binwrap-0.2.3.tgz", - "integrity": "sha512-N4Pm7iyDEv0BrAMs+dny8WQa+e0nNTdzn2ODkf/MM6XBtKSCxCSUA1ZOQGoc1n7mUqdgOS5pwjsW91rmXVxy2Q==", - "dev": true, - "dependencies": { - "request": "^2.88.0", - "tar": "^6.1.0", - "unzip-stream": "^0.3.1" - }, - "bin": { - "binwrap-install": "bin/binwrap-install", - "binwrap-prepare": "bin/binwrap-prepare", - "binwrap-test": "bin/binwrap-test" - } - }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -2383,6 +2643,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2461,15 +2722,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "dev": true, - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2565,6 +2817,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" @@ -2610,30 +2863,13 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case-first": "^2.0.2" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dev": true, - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, "node_modules/chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", @@ -2653,6 +2889,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, "dependencies": { "camel-case": "^4.1.2", "capital-case": "^1.0.4", @@ -2677,6 +2914,11 @@ "node": ">=10" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "node_modules/chokidar": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", @@ -2698,15 +2940,6 @@ "fsevents": "~2.3.1" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/ci-info": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", @@ -2752,13 +2985,32 @@ "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", "dev": true }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "engines": { - "node": ">=6" + "node": ">= 10" } }, "node_modules/cliui": { @@ -3032,6 +3284,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -3218,22 +3471,11 @@ "node": ">=8" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/data-uri-to-buffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "dev": true, "engines": { "node": ">= 12" } @@ -3298,9 +3540,9 @@ "dev": true }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { "node": ">=0.10" @@ -3578,6 +3820,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -3610,6 +3853,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -3664,16 +3908,6 @@ "object.defaults": "^1.1.0" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3686,19 +3920,22 @@ "dev": true }, "node_modules/elm": { - "version": "0.19.1-5", - "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-5.tgz", - "integrity": "sha512-dyBoPvFiNLvxOStQJdyq28gZEjS/enZXdZ5yyCtNtDEMbFJJVQq4pYNRKvhrKKdlxNot6d96iQe1uczoqO5yvA==", + "version": "0.19.1-6", + "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-6.tgz", + "integrity": "sha512-mKYyierHICPdMx/vhiIacdPmTPnh889gjHOZ75ZAoCxo3lZmSWbGP8HMw78wyctJH0HwvTmeKhlYSWboQNYPeQ==", "dev": true, "hasInstallScript": true, - "dependencies": { - "request": "^2.88.0" - }, "bin": { "elm": "bin/elm" }, "engines": { "node": ">=7.0.0" + }, + "optionalDependencies": { + "@elm_binaries/darwin_arm64": "0.19.1-0", + "@elm_binaries/darwin_x64": "0.19.1-0", + "@elm_binaries/linux_x64": "0.19.1-0", + "@elm_binaries/win32_x64": "0.19.1-0" } }, "node_modules/elm-doc-preview": { @@ -3764,16 +4001,20 @@ } }, "node_modules/elm-format": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/elm-format/-/elm-format-0.8.5.tgz", - "integrity": "sha512-/Mjwz5RhJ8cdcMsHT98AEKprSIHyRde+URIPvnHez9WH7Xp+rFCOJx0FNMPIYrbHE9Ei7HDSVwhjDP0i+mlvpQ==", + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/elm-format/-/elm-format-0.8.7.tgz", + "integrity": "sha512-sVzFXfWnb+6rzXK+q3e3Ccgr6/uS5mFbFk1VSmigC+x2XZ28QycAa7lS8owl009ALPhRQk+pZ95Eq5ANjpEZsQ==", "dev": true, "hasInstallScript": true, - "dependencies": { - "binwrap": "^0.2.3" - }, "bin": { "elm-format": "bin/elm-format" + }, + "optionalDependencies": { + "@avh4/elm-format-darwin-arm64": "0.8.7-2", + "@avh4/elm-format-darwin-x64": "0.8.7-2", + "@avh4/elm-format-linux-arm64": "0.8.7-2", + "@avh4/elm-format-linux-x64": "0.8.7-2", + "@avh4/elm-format-win32-x64": "0.8.7-2" } }, "node_modules/elm-test": { @@ -3826,9 +4067,9 @@ } }, "node_modules/elm-tooling": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/elm-tooling/-/elm-tooling-1.7.0.tgz", - "integrity": "sha512-EHZ54voWrG3BhUONbH/wFw5U95H6N7R4QFgXHDrPIaDBDdeyNkpFu4QWArSWkhzxyCF7hqT8ya2yy7SferDsgg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/elm-tooling/-/elm-tooling-1.15.0.tgz", + "integrity": "sha512-quRE5LGJyrkPBoJ3MvFQ5RGgf80J0L0d3NkduStvXh4TmZuMXNC3Z/l2ZRoq2UTUaNWeYfO1Zx5wns1AvsTrnw==", "dev": true, "bin": { "elm-tooling": "index.js" @@ -3929,6 +4170,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } @@ -4280,6 +4522,30 @@ "node": ">=0.10.0" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -4361,15 +4627,6 @@ "node": ">=0.10.0" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, "node_modules/fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -4394,6 +4651,7 @@ "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4409,6 +4667,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -4433,6 +4692,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -4450,6 +4710,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, "funding": [ { "type": "github", @@ -4468,6 +4729,20 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -4479,6 +4754,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4650,33 +4926,11 @@ "node": ">=0.10.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, "dependencies": { "fetch-blob": "^3.1.2" }, @@ -4726,18 +4980,6 @@ "node": ">=10" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", @@ -4820,6 +5062,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -4878,15 +5121,6 @@ "node": ">=0.10.0" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -4911,6 +5145,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -5888,51 +6123,6 @@ "node": ">= 0.10" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/har-validator/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -6060,6 +6250,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, "dependencies": { "capital-case": "^1.0.4", "tslib": "^2.0.3" @@ -6175,21 +6366,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -6250,6 +6426,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, "engines": { "node": ">= 4" } @@ -6312,6 +6489,85 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/inquirer": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.0.0.tgz", + "integrity": "sha512-ON8pEJPPCdyjxj+cxsYRe6XfCJepTxANdNnTebsTuQgXpRyZRRT9t4dJwjRubgmvn20CLSEnozRUayXyM9VTXA==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.6", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", @@ -6486,6 +6742,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -6512,6 +6769,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -6532,6 +6790,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } @@ -6717,12 +6976,6 @@ "node": ">=6" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -6749,9 +7002,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -7399,9 +7652,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -7509,7 +7762,8 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "3.13.1", @@ -7533,12 +7787,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -7599,29 +7847,6 @@ "node": ">= 6" } }, - "node_modules/jsdom/node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsdom/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -7663,12 +7888,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -7692,21 +7911,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/just-debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", @@ -7741,6 +7945,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, "engines": { "node": ">=6" } @@ -7917,8 +8122,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -7961,6 +8165,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -8002,9 +8207,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -8157,6 +8362,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "engines": { "node": ">= 8" } @@ -8324,7 +8530,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "engines": { "node": ">=6" } @@ -8371,46 +8576,21 @@ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minimisted": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", - "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - } - }, - "node_modules/minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" }, "engines": { - "node": ">=8" + "node": ">= 6" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", "dev": true, "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" + "minimist": "^1.2.5" } }, "node_modules/mixin-deep": { @@ -8775,6 +8955,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, "bin": { "mustache": "bin/mustache" } @@ -8788,6 +8969,11 @@ "node": ">= 0.10" } }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/nan": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", @@ -8859,6 +9045,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -8868,6 +9055,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, "funding": [ { "type": "github", @@ -8959,6 +9147,7 @@ "version": "3.2.8", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.8.tgz", "integrity": "sha512-KtpD1YhGszhntMpBDyp5lyagk8KIMopC1LEb7cQUAh7zcosaX5uK8HnbNb2i3NTQK3sIawCItS0uFC3QzcLHdg==", + "dev": true, "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", @@ -8988,6 +9177,7 @@ "version": "0.7.3", "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==", + "dev": true, "engines": { "node": ">=6" } @@ -9061,15 +9251,6 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -9232,7 +9413,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -9324,6 +9504,14 @@ "node": ">=0.10.0" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -9397,9 +9585,9 @@ } }, "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -9415,6 +9603,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -9488,6 +9677,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -9506,6 +9696,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -9580,25 +9771,22 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "engines": { "node": ">=8" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -9779,6 +9967,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -9844,14 +10033,11 @@ "node": ">=6" } }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true }, "node_modules/quick-lru": { "version": "4.0.1", @@ -10166,52 +10352,11 @@ "node": ">= 0.10" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -10224,6 +10369,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -10312,6 +10463,18 @@ "lowercase-keys": "^1.0.0" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -10325,6 +10488,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -10342,10 +10506,28 @@ "rimraf": "bin.js" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } }, "node_modules/safe-buffer": { "version": "5.2.1", @@ -10393,9 +10575,9 @@ } }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -10461,6 +10643,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -10640,8 +10823,7 @@ "node_modules/signal-exit": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", - "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", - "dev": true + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -10701,7 +10883,8 @@ "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true }, "node_modules/slash": { "version": "3.0.0", @@ -10716,6 +10899,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -10970,31 +11154,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -11242,35 +11401,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/temp": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", @@ -11323,8 +11453,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "node_modules/through2": { "version": "4.0.2", @@ -11444,6 +11573,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -11503,16 +11633,27 @@ } }, "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=0.8" + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" } }, "node_modules/tr46": { @@ -11527,15 +11668,6 @@ "node": ">=8" } }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -11590,9 +11722,9 @@ } }, "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -11666,24 +11798,7 @@ "node_modules/tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "dev": true }, "node_modules/type": { @@ -11934,16 +12049,6 @@ "node": ">=0.10.0" } }, - "node_modules/unzip-stream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.1.tgz", - "integrity": "sha512-RzaGXLNt+CW+T41h1zl6pGz3EaeVhYlK+rdAap+7DxW5kqsqePO8kRtWPaCiVqdhZc86EctSPVYNix30YOMzmw==", - "dev": true, - "dependencies": { - "binary": "^0.3.0", - "mkdirp": "^0.5.1" - } - }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -11958,6 +12063,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -11966,6 +12072,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -11985,6 +12092,16 @@ "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -12091,20 +12208,6 @@ "node": ">= 0.8" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "node_modules/vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -12275,6 +12378,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==", + "dev": true, "engines": { "node": ">=14.0.0" } @@ -12283,6 +12387,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz", "integrity": "sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==", + "dev": true, "dependencies": { "vscode-languageserver-protocol": "3.17.2" }, @@ -12294,6 +12399,7 @@ "version": "3.17.2", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz", "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==", + "dev": true, "dependencies": { "vscode-jsonrpc": "8.0.2", "vscode-languageserver-types": "3.17.2" @@ -12302,12 +12408,14 @@ "node_modules/vscode-languageserver-textdocument": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" + "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", + "dev": true }, "node_modules/vscode-languageserver-types": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", - "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" + "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==", + "dev": true }, "node_modules/w3c-hr-time": { "version": "1.0.2", @@ -12343,6 +12451,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true, "engines": { "node": ">= 8" } @@ -12410,9 +12519,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12428,6 +12537,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -12444,6 +12554,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -12452,6 +12563,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -12460,6 +12572,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -12473,6 +12586,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -12553,6 +12667,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "engines": { "node": ">=10" } @@ -12715,6 +12830,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "redistributable/TypeSpec/sdk": { + "name": "@morphir/typespec-sdk", + "version": "0.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@typespec/compiler": "latest" + } } }, "dependencies": { @@ -12727,10 +12851,46 @@ "@jridgewell/trace-mapping": "^0.3.0" } }, + "@avh4/elm-format-darwin-arm64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-darwin-arm64/-/elm-format-darwin-arm64-0.8.7-2.tgz", + "integrity": "sha512-F5JD44mJ3KX960J5GkXMfh1/dtkXuPcQpX2EToHQKjLTZUfnhZ++ytQQt0gAvrJ0bzoOvhNzjNjUHDA1ruTVbg==", + "dev": true, + "optional": true + }, + "@avh4/elm-format-darwin-x64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-darwin-x64/-/elm-format-darwin-x64-0.8.7-2.tgz", + "integrity": "sha512-4pfF1cl0KyTion+7Mg4XKM3yi4Yc7vP76Kt/DotLVGJOSag4ISGic1og2mt8RZZ7XArybBmHNyYkiUbe/cEiCw==", + "dev": true, + "optional": true + }, + "@avh4/elm-format-linux-arm64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-linux-arm64/-/elm-format-linux-arm64-0.8.7-2.tgz", + "integrity": "sha512-WkVmuce2zU6s9dupHhqPc886Vaqpea8dZlxv2fpZ4wSzPUbiiKHoHZzoVndMIMTUL0TZukP3Ps0n/lWO5R5+FA==", + "dev": true, + "optional": true + }, + "@avh4/elm-format-linux-x64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-linux-x64/-/elm-format-linux-x64-0.8.7-2.tgz", + "integrity": "sha512-kmncfJrTBjVT94JtQvMf4M5Pn2Yl0sZt3wo7AzgFiDnB/CiZ+KjJyXuWM64NeGiv4MQqzPq65tsFXUH1CIJeiQ==", + "dev": true, + "optional": true + }, + "@avh4/elm-format-win32-x64": { + "version": "0.8.7-2", + "resolved": "https://registry.npmjs.org/@avh4/elm-format-win32-x64/-/elm-format-win32-x64-0.8.7-2.tgz", + "integrity": "sha512-sBdMBGq/8mD8Y5C+fIr5vlb3N50yB7S1MfgeAq2QEbvkr/sKrCZI540i43lZDH9gWsfA1w2W8wCe0penFYzsGw==", + "dev": true, + "optional": true + }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, "requires": { "@babel/highlight": "^7.18.6" } @@ -12780,22 +12940,23 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { @@ -12811,49 +12972,36 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-imports": { @@ -12897,18 +13045,25 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true }, "@babel/helper-validator-option": { "version": "7.16.7", @@ -12928,12 +13083,13 @@ } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -12941,6 +13097,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -12949,6 +13106,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -12959,6 +13117,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -12966,17 +13125,20 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -12984,9 +13146,9 @@ } }, "@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -13107,34 +13269,141 @@ } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -13144,21 +13413,37 @@ "ms": "2.1.2" } }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -13192,6 +13477,34 @@ "@types/hammerjs": "^2.0.36" } }, + "@elm_binaries/darwin_arm64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/darwin_arm64/-/darwin_arm64-0.19.1-0.tgz", + "integrity": "sha512-mjbsH7BNHEAmoE2SCJFcfk5fIHwFIpxtSgnEAqMsVLpBUFoEtAeX+LQ+N0vSFJB3WAh73+QYx/xSluxxLcL6dA==", + "dev": true, + "optional": true + }, + "@elm_binaries/darwin_x64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/darwin_x64/-/darwin_x64-0.19.1-0.tgz", + "integrity": "sha512-QGUtrZTPBzaxgi9al6nr+9313wrnUVHuijzUK39UsPS+pa+n6CmWyV/69sHZeX9qy6UfeugE0PzF3qcUiy2GDQ==", + "dev": true, + "optional": true + }, + "@elm_binaries/linux_x64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/linux_x64/-/linux_x64-0.19.1-0.tgz", + "integrity": "sha512-T1ZrWVhg2kKAsi8caOd3vp/1A3e21VuCpSG63x8rDie50fHbCytTway9B8WHEdnBFv4mYWiA68dzGxYCiFmU2w==", + "dev": true, + "optional": true + }, + "@elm_binaries/win32_x64": { + "version": "0.19.1-0", + "resolved": "https://registry.npmjs.org/@elm_binaries/win32_x64/-/win32_x64-0.19.1-0.tgz", + "integrity": "sha512-yDleiXqSE9EcqKtd9SkC/4RIW8I71YsXzMPL79ub2bBPHjWTcoyyeBbYjoOB9SxSlArJ74HaoBApzT6hY7Zobg==", + "dev": true, + "optional": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -13472,32 +13785,47 @@ "chalk": "^4.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz", - "integrity": "sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz", - "integrity": "sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@morphir/typespec-sdk": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@morphir/typespec-sdk/-/typespec-sdk-0.1.0.tgz", - "integrity": "sha512-x6qCqOA4Sh+Wj7IV4bxz0R5jtMzlCbUHdq2UYS49I1UWCdKD155WMzfitb+950aeupMskzfJDziiXkrtVEKEhw==", + "version": "file:redistributable/TypeSpec/sdk", "requires": { "@typespec/compiler": "latest" } @@ -13506,6 +13834,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dev": true, "requires": { "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" @@ -13514,12 +13843,14 @@ "@nodelib/fs.stat": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true }, "@nodelib/fs.walk": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" @@ -13654,6 +13985,16 @@ "integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==", "peer": true }, + "@types/inquirer": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.3.tgz", + "integrity": "sha512-CzNkWqQftcmk2jaCWdBTf9Sm7xSw4rkI1zpU/Udw3HX5//adEZUIm9STtoRP1qgWj0CWQtJ9UTvqmO2NNjhMJw==", + "dev": true, + "requires": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -13730,6 +14071,15 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/through": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", + "integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -13749,6 +14099,7 @@ "version": "0.42.0", "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.42.0.tgz", "integrity": "sha512-eONMtlDQ5Bpge4lcprI06mnfW924bo23LVNNKTdC1/1g1iQWPGH2fNpstEomumzOvTNwINh3xKtwkJ5huckBUQ==", + "dev": true, "requires": { "@babel/code-frame": "~7.18.6", "ajv": "~8.11.2", @@ -13770,12 +14121,14 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -13786,6 +14139,7 @@ "version": "13.1.3", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, "requires": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", @@ -13797,12 +14151,14 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { "argparse": "^2.0.1" } @@ -13810,22 +14166,26 @@ "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true }, "prettier": { "version": "2.8.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==" + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "dev": true }, "slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13836,6 +14196,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -13844,6 +14205,7 @@ "version": "17.6.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, "requires": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -13857,7 +14219,8 @@ "yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true } } }, @@ -13868,9 +14231,9 @@ "dev": true }, "@vercel/ncc": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.24.1.tgz", - "integrity": "sha512-r9m7brz2hNmq5TF3sxrK4qR/FhXn44XIMglQUir4sT7Sh5GOaYXlMYikHFwJStf8rmQGTlvOoBXt4yHVonRG8A==", + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz", + "integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==", "dev": true }, "abab": { @@ -13992,7 +14355,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "requires": { "type-fest": "^0.21.3" }, @@ -14000,8 +14362,7 @@ "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" } } }, @@ -14068,7 +14429,8 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "arr-diff": { "version": "4.0.0", @@ -14195,21 +14557,6 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -14272,18 +14619,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "babel-jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", @@ -14439,25 +14774,6 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -14474,17 +14790,6 @@ "file-uri-to-path": "1.0.0" } }, - "binwrap": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/binwrap/-/binwrap-0.2.3.tgz", - "integrity": "sha512-N4Pm7iyDEv0BrAMs+dny8WQa+e0nNTdzn2ODkf/MM6XBtKSCxCSUA1ZOQGoc1n7mUqdgOS5pwjsW91rmXVxy2Q==", - "dev": true, - "requires": { - "request": "^2.88.0", - "tar": "^6.1.0", - "unzip-stream": "^0.3.1" - } - }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -14533,6 +14838,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -14592,12 +14898,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", - "dev": true - }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -14671,6 +14971,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, "requires": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" @@ -14703,27 +15004,13 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case-first": "^2.0.2" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, "chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", @@ -14737,6 +15024,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, "requires": { "camel-case": "^4.1.2", "capital-case": "^1.0.4", @@ -14758,6 +15046,11 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "chokidar": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", @@ -14774,12 +15067,6 @@ "readdirp": "~3.5.0" } }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true - }, "ci-info": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", @@ -14827,6 +15114,19 @@ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -15055,6 +15355,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -15213,19 +15514,11 @@ "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "data-uri-to-buffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==" + "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "dev": true }, "data-urls": { "version": "2.0.0", @@ -15277,9 +15570,9 @@ "dev": true }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, "decompress-response": { @@ -15483,6 +15776,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "requires": { "path-type": "^4.0.0" } @@ -15508,6 +15802,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -15564,16 +15859,6 @@ "object.defaults": "^1.1.0" } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -15586,12 +15871,15 @@ "dev": true }, "elm": { - "version": "0.19.1-5", - "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-5.tgz", - "integrity": "sha512-dyBoPvFiNLvxOStQJdyq28gZEjS/enZXdZ5yyCtNtDEMbFJJVQq4pYNRKvhrKKdlxNot6d96iQe1uczoqO5yvA==", + "version": "0.19.1-6", + "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-6.tgz", + "integrity": "sha512-mKYyierHICPdMx/vhiIacdPmTPnh889gjHOZ75ZAoCxo3lZmSWbGP8HMw78wyctJH0HwvTmeKhlYSWboQNYPeQ==", "dev": true, "requires": { - "request": "^2.88.0" + "@elm_binaries/darwin_arm64": "0.19.1-0", + "@elm_binaries/darwin_x64": "0.19.1-0", + "@elm_binaries/linux_x64": "0.19.1-0", + "@elm_binaries/win32_x64": "0.19.1-0" } }, "elm-doc-preview": { @@ -15643,12 +15931,16 @@ } }, "elm-format": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/elm-format/-/elm-format-0.8.5.tgz", - "integrity": "sha512-/Mjwz5RhJ8cdcMsHT98AEKprSIHyRde+URIPvnHez9WH7Xp+rFCOJx0FNMPIYrbHE9Ei7HDSVwhjDP0i+mlvpQ==", + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/elm-format/-/elm-format-0.8.7.tgz", + "integrity": "sha512-sVzFXfWnb+6rzXK+q3e3Ccgr6/uS5mFbFk1VSmigC+x2XZ28QycAa7lS8owl009ALPhRQk+pZ95Eq5ANjpEZsQ==", "dev": true, "requires": { - "binwrap": "^0.2.3" + "@avh4/elm-format-darwin-arm64": "0.8.7-2", + "@avh4/elm-format-darwin-x64": "0.8.7-2", + "@avh4/elm-format-linux-arm64": "0.8.7-2", + "@avh4/elm-format-linux-x64": "0.8.7-2", + "@avh4/elm-format-win32-x64": "0.8.7-2" } }, "elm-test": { @@ -15688,9 +15980,9 @@ } }, "elm-tooling": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/elm-tooling/-/elm-tooling-1.7.0.tgz", - "integrity": "sha512-EHZ54voWrG3BhUONbH/wFw5U95H6N7R4QFgXHDrPIaDBDdeyNkpFu4QWArSWkhzxyCF7hqT8ya2yy7SferDsgg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/elm-tooling/-/elm-tooling-1.15.0.tgz", + "integrity": "sha512-quRE5LGJyrkPBoJ3MvFQ5RGgf80J0L0d3NkduStvXh4TmZuMXNC3Z/l2ZRoq2UTUaNWeYfO1Zx5wns1AvsTrnw==", "dev": true }, "emittery": { @@ -15774,7 +16066,8 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, "escape-html": { "version": "1.0.3", @@ -16046,6 +16339,26 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + } + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -16111,12 +16424,6 @@ } } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -16138,6 +16445,7 @@ "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -16150,6 +16458,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, "requires": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -16173,6 +16482,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, "requires": { "reusify": "^1.0.4" } @@ -16190,11 +16500,20 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, "requires": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -16206,6 +16525,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -16339,30 +16659,14 @@ "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", "dev": true, "requires": { - "for-in": "^1.0.1" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "for-in": "^1.0.1" } }, "formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, "requires": { "fetch-blob": "^3.1.2" } @@ -16397,15 +16701,6 @@ "universalify": "^2.0.0" } }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, "fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", @@ -16476,7 +16771,8 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "get-intrinsic": { "version": "1.1.2", @@ -16514,15 +16810,6 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -16541,6 +16828,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -17315,42 +17603,6 @@ "glogg": "^1.0.0" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } - } - }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -17446,6 +17698,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, "requires": { "capital-case": "^1.0.4", "tslib": "^2.0.3" @@ -17539,17 +17792,6 @@ } } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -17594,7 +17836,8 @@ "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true }, "import-local": { "version": "3.1.0", @@ -17639,6 +17882,69 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "inquirer": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.0.0.tgz", + "integrity": "sha512-ON8pEJPPCdyjxj+cxsYRe6XfCJepTxANdNnTebsTuQgXpRyZRRT9t4dJwjRubgmvn20CLSEnozRUayXyM9VTXA==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.6", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", @@ -17770,7 +18076,8 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -17788,6 +18095,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -17801,7 +18109,8 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-path-cwd": { "version": "2.2.0", @@ -17938,12 +18247,6 @@ } } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -17964,9 +18267,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -18477,9 +18780,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -18563,7 +18866,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "3.13.1", @@ -18586,12 +18890,6 @@ } } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -18637,23 +18935,6 @@ "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true } } }, @@ -18692,12 +18973,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -18713,18 +18988,6 @@ "universalify": "^2.0.0" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, "just-debounce": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", @@ -18755,7 +19018,8 @@ "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true }, "last-run": { "version": "1.1.1", @@ -18900,8 +19164,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.memoize": { "version": "4.1.2", @@ -18935,6 +19198,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, "requires": { "tslib": "^2.0.3" } @@ -18964,9 +19228,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -19089,7 +19353,8 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true }, "methods": { "version": "1.1.2", @@ -19222,8 +19487,7 @@ "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, "mimic-response": { "version": "1.0.1", @@ -19272,25 +19536,6 @@ "minimist": "^1.2.5" } }, - "minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -19549,7 +19794,8 @@ "mustache": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true }, "mute-stdout": { "version": "1.0.1", @@ -19557,6 +19803,11 @@ "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "nan": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", @@ -19616,6 +19867,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, "requires": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -19624,7 +19876,8 @@ "node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true }, "node-elm-compiler": { "version": "5.0.5", @@ -19687,6 +19940,7 @@ "version": "3.2.8", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.8.tgz", "integrity": "sha512-KtpD1YhGszhntMpBDyp5lyagk8KIMopC1LEb7cQUAh7zcosaX5uK8HnbNb2i3NTQK3sIawCItS0uFC3QzcLHdg==", + "dev": true, "requires": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", @@ -19708,7 +19962,8 @@ "node-watch": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", - "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==" + "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==", + "dev": true }, "normalize-package-data": { "version": "2.5.0", @@ -19764,12 +20019,6 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -19895,7 +20144,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "requires": { "mimic-fn": "^2.1.0" } @@ -19973,6 +20221,11 @@ "lcid": "^1.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -20025,9 +20278,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -20042,6 +20295,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, "requires": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -20097,6 +20351,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -20112,6 +20367,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, "requires": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -20170,23 +20426,20 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true }, "pify": { "version": "2.3.0", @@ -20306,6 +20559,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -20364,10 +20618,10 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, "quick-lru": { @@ -20622,52 +20876,23 @@ "remove-trailing-separator": "^1.1.0" } }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", @@ -20734,6 +20959,15 @@ "lowercase-keys": "^1.0.0" } }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -20743,7 +20977,8 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true }, "rimraf": { "version": "2.6.3", @@ -20754,10 +20989,25 @@ "glob": "^7.1.3" } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } }, "safe-buffer": { "version": "5.2.1", @@ -20788,9 +21038,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "semver-greatest-satisfied-range": { @@ -20843,6 +21093,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -20993,8 +21244,7 @@ "signal-exit": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", - "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", - "dev": true + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==" }, "simple-concat": { "version": "1.0.1", @@ -21033,7 +21283,8 @@ "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true }, "slash": { "version": "3.0.0", @@ -21045,6 +21296,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, "requires": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -21262,23 +21514,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -21474,28 +21709,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, "temp": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", @@ -21536,8 +21749,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "4.0.2", @@ -21634,6 +21846,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -21686,13 +21899,23 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true + } } }, "tr46": { @@ -21704,12 +21927,6 @@ "punycode": "^2.1.1" } }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true - }, "trim-newlines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", @@ -21733,9 +21950,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -21780,21 +21997,7 @@ "tslib": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "dev": true }, "type": { @@ -21999,16 +22202,6 @@ } } }, - "unzip-stream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.1.tgz", - "integrity": "sha512-RzaGXLNt+CW+T41h1zl6pGz3EaeVhYlK+rdAap+7DxW5kqsqePO8kRtWPaCiVqdhZc86EctSPVYNix30YOMzmw==", - "dev": true, - "requires": { - "binary": "^0.3.0", - "mkdirp": "^0.5.1" - } - }, "upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -22019,6 +22212,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, "requires": { "tslib": "^2.0.3" } @@ -22027,6 +22221,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, "requires": { "tslib": "^2.0.3" } @@ -22045,6 +22240,16 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -22126,17 +22331,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "vinyl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", @@ -22264,12 +22458,14 @@ "vscode-jsonrpc": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", - "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==" + "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==", + "dev": true }, "vscode-languageserver": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-8.0.2.tgz", "integrity": "sha512-bpEt2ggPxKzsAOZlXmCJ50bV7VrxwCS5BI4+egUmure/oI/t4OlFzi/YNtVvY24A2UDOZAgwFGgnZPwqSJubkA==", + "dev": true, "requires": { "vscode-languageserver-protocol": "3.17.2" } @@ -22278,6 +22474,7 @@ "version": "3.17.2", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz", "integrity": "sha512-8kYisQ3z/SQ2kyjlNeQxbkkTNmVFoQCqkmGrzLH6A9ecPlgTbp3wDTnUNqaUxYr4vlAcloxx8zwy7G5WdguYNg==", + "dev": true, "requires": { "vscode-jsonrpc": "8.0.2", "vscode-languageserver-types": "3.17.2" @@ -22286,12 +22483,14 @@ "vscode-languageserver-textdocument": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", - "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" + "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", + "dev": true }, "vscode-languageserver-types": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz", - "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==" + "integrity": "sha512-zHhCWatviizPIq9B7Vh9uvrH6x3sK8itC84HkamnBWoDFJtzBf7SWlpLCZUit72b3os45h6RWQNC9xHRDF8dRA==", + "dev": true }, "w3c-hr-time": { "version": "1.0.2", @@ -22323,7 +22522,8 @@ "web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true }, "webidl-conversions": { "version": "6.1.0", @@ -22376,9 +22576,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "workerpool": { @@ -22391,6 +22591,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -22400,17 +22601,20 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -22421,6 +22625,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -22479,7 +22684,8 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true }, "yallist": { "version": "4.0.0", diff --git a/package.json b/package.json index bf6c0f9fe..25d955cbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "morphir-elm", - "version": "2.81.0", + "version": "2.87.6", "description": "Elm bindings for Morphir", "types": "lib/dist/main.d.ts", "main": "lib/dist/main.js", @@ -19,7 +19,8 @@ "ncc-morphir-server": "ncc build cli/morphir-elm-develop.js -o dist/morphir-server", "build": "gulp && npm run ncc-morphir && npm run ncc-morphir-server && npx jest && gulp test", "test-coverage": "elm-coverage src/ --open", - "build-value-editor": "elm make cli/src/Morphir/Web/Editor.elm --output=cli/web/valueEditor.js" + "build-value-editor": "elm make cli/src/Morphir/Web/Editor.elm --output=cli/web/valueEditor.js", + "setup-elm-tooling": "elm-tooling install" }, "repository": { "type": "git", @@ -30,6 +31,10 @@ "morphir-dapr": "cli/morphir-dapr.js", "morphir": "cli2/lib/morphir.js" }, + "engines": { + "npm": "*", + "node": "*" + }, "files": [ "cli/cli.js", "cli/morphir-elm.js", @@ -60,15 +65,18 @@ }, "homepage": "https://github.com/Morgan-Stanley/morphir-elm#readme", "devDependencies": { + "@morphir/typespec-sdk": "file:redistributable/TypeSpec/sdk", + "@types/inquirer": "^9.0.3", "@types/jest": "^27.4.0", "@types/mocha": "^9.0.0", "@typespec/compiler": "^0.42.0", - "@vercel/ncc": "^0.24.1", + "@vercel/ncc": "^0.38.1", "del-cli": "3.0.1", "elm": "^0.19.1-5", "elm-doc-preview": "^5.0.5", "elm-format": "^0.8.5", "elm-test": "^0.19.1-revision6", + "elm-tooling": "^1.15.0", "execa": "^5.1.1", "gulp": "^4.0.2", "gulp-mocha": "^8.0.0", @@ -85,7 +93,6 @@ "typescript": "^4.4.3" }, "dependencies": { - "@morphir/typespec-sdk": "^0.1.0", "ajv": "^8.10.0", "ajv-formats": "^2.1.1", "chalk": "^4.1.1", @@ -94,6 +101,7 @@ "express": "^4.18.2", "fs-extra": "^9.1.0", "get-stdin": "^8.0.0", + "inquirer": "^8.0.0", "log-timestamp": "^0.3.0", "prettier": "^2.4.1", "vis-network": "^9.1.2" diff --git a/redistributable/Snowpark/decorations/elm.json b/redistributable/Snowpark/decorations/elm.json new file mode 100644 index 000000000..ce2a08dc7 --- /dev/null +++ b/redistributable/Snowpark/decorations/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/redistributable/Snowpark/decorations/morphir.json b/redistributable/Snowpark/decorations/morphir.json new file mode 100644 index 000000000..437165aec --- /dev/null +++ b/redistributable/Snowpark/decorations/morphir.json @@ -0,0 +1,4 @@ +{ + "name": "SnowparkGenCustomization", + "sourceDirectory": "src" +} diff --git a/redistributable/Snowpark/decorations/src/SnowparkGenCustomization/Decorations.elm b/redistributable/Snowpark/decorations/src/SnowparkGenCustomization/Decorations.elm new file mode 100644 index 000000000..fc1345efe --- /dev/null +++ b/redistributable/Snowpark/decorations/src/SnowparkGenCustomization/Decorations.elm @@ -0,0 +1,5 @@ +module SnowparkGenCustomization.Decorations exposing (..) + +type GenerationCustomization = + InlineElement + | CacheResult diff --git a/redistributable/TypeSpec/sdk/main.tsp b/redistributable/TypeSpec/sdk/main.tsp index de0c10c20..23e74748b 100644 --- a/redistributable/TypeSpec/sdk/main.tsp +++ b/redistributable/TypeSpec/sdk/main.tsp @@ -27,16 +27,13 @@ namespace Decimal { namespace LocalDate { scalar LocalDate extends plainDate; + scalar Month extends string; } namespace LocalTime { scalar LocalTime extends plainTime; } -namespace Month { - scalar Month extends string; -} - // Optional Types namespace Maybe { diff --git a/src/Morphir/Elm/IncrementalFrontend/Mapper.elm b/src/Morphir/Elm/IncrementalFrontend/Mapper.elm index 7a26215a3..3514b80d6 100644 --- a/src/Morphir/Elm/IncrementalFrontend/Mapper.elm +++ b/src/Morphir/Elm/IncrementalFrontend/Mapper.elm @@ -311,8 +311,18 @@ mapExpression resolveReferenceName moduleName variables (Node range expr) = Ok (Value.Literal defaultValueAttribute (Literal.FloatLiteral value)) Expression.Negation arg -> - mapExpression resolveReferenceName moduleName variables arg - |> Result.map (SDKBasics.negate defaultValueAttribute defaultValueAttribute) + case arg of + Node _ exp -> + case exp of + Integer value -> + Ok (Value.Literal defaultValueAttribute (Literal.WholeNumberLiteral -value)) + + Floatable value -> + Ok (Value.Literal defaultValueAttribute (Literal.FloatLiteral -value)) + + _ -> + mapExpression resolveReferenceName moduleName variables arg + |> Result.map (SDKBasics.negate defaultValueAttribute defaultValueAttribute) Expression.Literal value -> Ok (Value.Literal defaultValueAttribute (Literal.StringLiteral value)) diff --git a/src/Morphir/IR/Decoration.elm b/src/Morphir/IR/Decoration.elm index 0852bb096..66ea7a9c9 100644 --- a/src/Morphir/IR/Decoration.elm +++ b/src/Morphir/IR/Decoration.elm @@ -1,4 +1,14 @@ -module Morphir.IR.Decoration exposing (..) +module Morphir.IR.Decoration exposing + ( DecorationID, AllDecorationConfigAndData, DecorationData, DecorationConfigAndData + , getDecoratedNodeIds, getNodeIdsDecoratedWithValue, filterDecorations + ) + +{-| Module to work with Decorations. A decoration is an additional piece of information added to your model that is not captured in the langauge + +@docs DecorationID, AllDecorationConfigAndData, DecorationData, DecorationConfigAndData +@docs getDecoratedNodeIds, getNodeIdsDecoratedWithValue, filterDecorations + +-} import Dict exposing (Dict) import Morphir.IR.Distribution @@ -8,18 +18,23 @@ import Morphir.IR.Value exposing (RawValue) import Morphir.SDK.Dict as SDKDict +{-| -} type alias DecorationID = String +{-| -} type alias AllDecorationConfigAndData = Dict DecorationID DecorationConfigAndData +{-| Represents the contend of a sidecar file. +-} type alias DecorationData = SDKDict.Dict NodeID RawValue +{-| -} type alias DecorationConfigAndData = { displayName : String , entryPoint : FQName @@ -41,6 +56,7 @@ getNodeIdsDecoratedWithValue : DecorationID -> RawValue -> AllDecorationConfigAn getNodeIdsDecoratedWithValue decorationId decorationValue allDecorationConfigData = filterDecorations decorationId (\_ v -> v == decorationValue) allDecorationConfigData + {-| Given a decoration type and a predicate, return a List of NodeIDs where the decoration satisfies the predicate. -} filterDecorations : DecorationID -> (NodeID -> RawValue -> Bool) -> AllDecorationConfigAndData -> List NodeID diff --git a/src/Morphir/IR/Decoration/Codec.elm b/src/Morphir/IR/Decoration/Codec.elm index b99bbc612..c8372816d 100644 --- a/src/Morphir/IR/Decoration/Codec.elm +++ b/src/Morphir/IR/Decoration/Codec.elm @@ -1,4 +1,14 @@ -module Morphir.IR.Decoration.Codec exposing (..) +module Morphir.IR.Decoration.Codec exposing + ( decodeNodeIDByValuePairs, decodeAllDecorationConfigAndData + , decodeDecorationValue, decodeDecorationData, decodeDecorationConfigAndData, encodeDecorationData + ) + +{-| Codecs for types in the `Morphir.IR.Decoration` module + +@docs decodeNodeIDByValuePairs, decodeAllDecorationConfigAndData +@docs decodeDecorationValue, decodeDecorationData, decodeDecorationConfigAndData, encodeDecorationData + +-} import Json.Decode as Decode import Json.Encode as Encode @@ -13,6 +23,7 @@ import Morphir.IR.Value as IRValue import Morphir.SDK.Dict as SDKDict +{-| -} decodeNodeIDByValuePairs : Decode.Decoder (SDKDict.Dict NodeID Decode.Value) decodeNodeIDByValuePairs = Decode.keyValuePairs Decode.value @@ -40,11 +51,13 @@ decodeNodeIDByValuePairs = |> Decode.map SDKDict.fromList +{-| -} decodeAllDecorationConfigAndData : Decode.Decoder AllDecorationConfigAndData decodeAllDecorationConfigAndData = Decode.dict decodeDecorationConfigAndData +{-| -} decodeDecorationValue : Distribution -> FQName -> Decode.Decoder IRValue.RawValue decodeDecorationValue distro entryPointFqn = let @@ -60,6 +73,7 @@ decodeDecorationValue distro entryPointFqn = |> resultToFailure +{-| -} decodeDecorationData : Distribution -> FQName -> Decode.Decoder DecorationData decodeDecorationData distro entryPointFqn = Decode.keyValuePairs (decodeDecorationValue distro entryPointFqn) @@ -87,6 +101,7 @@ decodeDecorationData distro entryPointFqn = |> Decode.map SDKDict.fromList +{-| -} decodeDecorationConfigAndData : Decode.Decoder DecorationConfigAndData decodeDecorationConfigAndData = let @@ -113,6 +128,7 @@ decodeDecorationConfigAndData = |> Decode.andThen identity +{-| -} encodeDecorationData : Distribution -> FQName -> DecorationData -> Encode.Value encodeDecorationData distribution entryPoint decorationData = let diff --git a/src/Morphir/IR/NodeId.elm b/src/Morphir/IR/NodeId.elm index 4a8ea5e85..6a739363f 100644 --- a/src/Morphir/IR/NodeId.elm +++ b/src/Morphir/IR/NodeId.elm @@ -1,4 +1,20 @@ -module Morphir.IR.NodeId exposing (Error(..), NodeID(..), NodePath, NodePathStep(..), getAttribute, getTypeAttributeByPath, getValueAttributeByPath, mapPatternAttributesWithNodePath, mapTypeAttributeWithNodePath, mapValueAttributesWithNodePath, nodeIdFromString, nodeIdToString, nodePathFromString, nodePathToString) +module Morphir.IR.NodeId exposing + ( NodeID(..), NodePath, NodePathStep(..) + , nodeIdFromString, nodeIdToString, nodePathFromString, nodePathToString, getAttribute + , mapPatternAttributesWithNodePath, mapTypeAttributeWithNodePath, mapValueAttributesWithNodePath + , getTypeAttributeByPath, getValueAttributeByPath + , Error(..) + ) + +{-| A data type that represents a node in the IR + +@docs NodeID, NodePath, NodePathStep +@docs nodeIdFromString, nodeIdToString, nodePathFromString, nodePathToString, getAttribute +@docs mapPatternAttributesWithNodePath, mapTypeAttributeWithNodePath, mapValueAttributesWithNodePath +@docs getTypeAttributeByPath, getValueAttributeByPath +@docs Error + +-} import Dict exposing (Dict) import List.Extra @@ -11,13 +27,7 @@ import Morphir.IR.Type as Type exposing (Field, Type(..)) import Morphir.IR.Value as Value exposing (Value(..)) -{-| - -@docs NodeID, NodePath, NodePathStep, Error - -@docs nodeIdFromString, nodeIdToString, nodePathFromString, nodePathToString, getAttribute, mapPatternAttributesWithNodePath, mapTypeAttributeWithNodePath, mapValueAttributesWithNodePath - -Represents a path in the IR. This is a recursive structure made up of the following +{-| Represents a path in the IR. This is a recursive structure made up of the following building blocks: - **ChildByName** traverses to a child node by name. It takes one argument @@ -50,17 +60,23 @@ type alias NodePath = List NodePathStep +{-| Represents a path to a child node +-} type NodePathStep = ChildByName Name | ChildByIndex Int +{-| Represents a node in the IR. Could be a Type, Value or Module +-} type NodeID = TypeID FQName NodePath | ValueID FQName NodePath | ModuleID ( Path, Path ) +{-| Represents an error that might occur during node operations +-} type Error = InvalidPath String | InvalidNodeID String @@ -91,7 +107,7 @@ nodeIdFromString str = in case String.split ":" str of [ packageName, moduleName ] -> - Ok (ModuleID ( [ packageName |> Name.fromString ], [ moduleName |> Name.fromString ] )) + Ok (ModuleID ( packageName |> Path.fromString, moduleName |> Path.fromString )) [ packageName, moduleName, localName ] -> if String.contains "#" localName then diff --git a/src/Morphir/IR/SDK.elm b/src/Morphir/IR/SDK.elm index d80923942..2ec1d5aba 100644 --- a/src/Morphir/IR/SDK.elm +++ b/src/Morphir/IR/SDK.elm @@ -33,7 +33,6 @@ import Morphir.IR.SDK.List as List import Morphir.IR.SDK.LocalDate as LocalDate import Morphir.IR.SDK.LocalTime as LocalTime import Morphir.IR.SDK.Maybe as Maybe -import Morphir.IR.SDK.Month as Month import Morphir.IR.SDK.Number as Number import Morphir.IR.SDK.Regex as Regex import Morphir.IR.SDK.Result as Result @@ -64,7 +63,6 @@ packageSpec = , ( [ [ "local", "date" ] ], LocalDate.moduleSpec ) , ( [ [ "local", "time" ] ], LocalTime.moduleSpec ) , ( [ [ "maybe" ] ], Maybe.moduleSpec ) - , ( [ [ "month" ] ], Month.moduleSpec ) , ( [ [ "result" ] ], Result.moduleSpec ) , ( [ [ "list" ] ], List.moduleSpec ) , ( [ [ "result", "list" ] ], ResultList.moduleSpec ) diff --git a/src/Morphir/IR/SDK/Decimal.elm b/src/Morphir/IR/SDK/Decimal.elm index 158109bd4..7026f5ced 100644 --- a/src/Morphir/IR/SDK/Decimal.elm +++ b/src/Morphir/IR/SDK/Decimal.elm @@ -46,7 +46,7 @@ moduleSpec = , vSpec "negate" [ ( "value", decimalType () ) ] (decimalType ()) , vSpec "mul" [ ( "a", decimalType () ), ( "b", decimalType () ) ] (decimalType ()) , vSpec "div" [ ( "a", decimalType () ), ( "b", decimalType () ) ] (maybeType () (decimalType ())) - , vSpec "divWithDefault" [ ( "default", decimalType () ), ( "a", decimalType () ), ( "b", decimalType () ) ] (maybeType () (decimalType ())) + , vSpec "divWithDefault" [ ( "default", decimalType () ), ( "a", decimalType () ), ( "b", decimalType () ) ] (decimalType ()) , vSpec "truncate" [ ( "d", decimalType () ) ] (decimalType ()) , vSpec "round" [ ( "d", decimalType () ) ] (decimalType ()) , vSpec "gt" [ ( "a", decimalType () ), ( "b", decimalType () ) ] (boolType ()) diff --git a/src/Morphir/IR/SDK/Dict.elm b/src/Morphir/IR/SDK/Dict.elm index c08ac42f1..7e16d01cf 100644 --- a/src/Morphir/IR/SDK/Dict.elm +++ b/src/Morphir/IR/SDK/Dict.elm @@ -29,8 +29,10 @@ import Morphir.IR.SDK.List exposing (listType) import Morphir.IR.SDK.Maybe exposing (just, maybeType, nothing) import Morphir.IR.Type as Type exposing (Specification(..), Type(..)) import Morphir.IR.Value as Value exposing (RawValue, Value) +import Morphir.SDK.Dict as SDKDict +import Morphir.SDK.ResultList as ResultList import Morphir.Value.Error exposing (Error(..)) -import Morphir.Value.Native as Native +import Morphir.Value.Native as Native exposing (eval1) import Morphir.Value.Native.Comparable exposing (compareValue) @@ -41,7 +43,7 @@ moduleName = typeSpec : Specification () typeSpec = - DerivedTypeSpecification [["comparable"], ["v"] ] + DerivedTypeSpecification [ [ "comparable" ], [ "v" ] ] { baseType = listType () (Type.Tuple () [ tVar "comparable", tVar "v" ]) , toBaseType = toFQName moduleName "toList" , fromBaseType = toFQName moduleName "fromList" @@ -149,7 +151,6 @@ fromListValue a list = Value.Apply a (Value.Reference a ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) list - nativeFunctions : List ( String, Native.Function ) nativeFunctions = [ ( "empty" @@ -300,6 +301,8 @@ nativeFunctions = Err (UnexpectedArguments [ dict ]) ) ) + + {- Query -} , ( "isEmpty" , Native.unaryStrict (\_ dict -> @@ -458,7 +461,7 @@ nativeFunctions = Err (UnexpectedArguments [ dict ]) ) ) - , ( "value" + , ( "values" , Native.unaryStrict (\_ dict -> case dict of @@ -488,12 +491,300 @@ nativeFunctions = Err (UnexpectedArguments [ dict ]) ) ) - , ( "toList", Native.unaryStrict (\_ arg -> - case arg of - Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) list -> - Ok list - _ -> - Err (UnexpectedArguments [ arg ]) - )) + , ( "toList" + , Native.unaryStrict + (\eval arg -> + case eval arg of + Ok (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) list) -> + Ok list + + e -> + let + _ = + Debug.log "err" e + in + Err (UnexpectedArguments [ arg |> Debug.log "toListErr" ]) + ) + ) , ( "fromList", Native.unaryStrict (\_ arg -> Ok (fromListValue () arg)) ) + + --, ( "map" + -- , Native.eval2 SDKDict.map + -- (Native.decodeFun2 Native.encodeRaw Native.encodeRaw Native.decodeRaw) + -- (Native.decodeDict Native.decodeRaw Native.decodeRaw) + -- (Native.encodeDict Native.encodeRaw Native.encodeRaw Native.encodeMaybeResult) + -- ) + , ( "map" + , \eval args -> + case args of + [ func, dict ] -> + case eval dict of + Ok (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg) -> + case arg of + Value.List _ list -> + let + map ls resList = + case ls of + [] -> + Ok resList + + (Value.Tuple _ [ key, value ]) :: rest -> + eval (Value.Apply () (Value.Apply () func key) value) + |> Result.map (\newValue -> resList ++ [ Value.Tuple () [ key, newValue ] ]) + |> Result.andThen (map rest) + + _ -> + Err TupleExpected + in + map list [] + |> Result.map (Value.List ()) + |> Result.map (fromListValue ()) + + _ -> + Err (ExpectedList arg) + + _ -> + Err (UnexpectedArguments [ dict ]) + + _ -> + Err (UnexpectedArguments (args |> Debug.log "args")) + ) + , ( "foldl" + , \eval args -> + case args of + [ func, acc, dict ] -> + case eval dict of + Ok (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg) -> + eval arg + |> Result.andThen + (\evaluatedDict -> + case evaluatedDict of + Value.List () list -> + eval acc + |> Result.andThen + (\evalAcc -> + let + foldl ls res = + case ls of + [] -> + Ok res + + head :: tail -> + case head of + Value.Tuple () [ key, value ] -> + --eval acc + -- |> Result.andThen + -- (\soFar -> + eval + (Value.Apply () + (Value.Apply () (Value.Apply () func key) value) + res + ) + |> Result.andThen (foldl tail) + + --) + _ -> + Err TupleExpected + in + foldl list evalAcc + ) + + _ -> + Err (ExpectedList evaluatedDict) + ) + + _ -> + Err (UnexpectedArguments [ dict ]) + + _ -> + Err (UnexpectedArguments args) + ) + , ( "foldr" + , \eval args -> + case args of + [ func, acc, dict ] -> + case dict of + Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg -> + eval arg + |> Debug.log "arg" + |> Result.andThen + (\evaluatedDict -> + case evaluatedDict of + Value.List () list -> + eval acc + |> Debug.log "acc" + |> Result.andThen + (\evalAcc -> + let + foldr ls res = + case ls |> Debug.log "todo" of + [] -> + Ok res + + head :: tail -> + foldr tail res + |> Debug.log "todo" + |> Result.andThen + (\result -> + case head of + Value.Tuple () [ key, value ] -> + eval + (Value.Apply () + (Value.Apply () + (Value.Apply () func key) + value + ) + result + ) + + _ -> + Err TupleExpected + ) + + --case head of + -- Value.Tuple () [ key, value ] -> + -- tailRes + -- |> Debug.log "tail" + -- |> Result.andThen + -- (\result -> + -- eval + -- (Value.Apply () + -- (Value.Apply () + -- (Value.Apply () func key) + -- value + -- ) + -- result + -- ) + -- ) + -- + -- _ -> + -- Err TupleExpected + in + foldr list evalAcc + ) + + _ -> + Err (ExpectedList evaluatedDict) + ) + + _ -> + Err (UnexpectedArguments [ dict ]) + + _ -> + Err (UnexpectedArguments args) + ) + , ( "filter" + , \eval args -> + case args of + [ func, dict ] -> + case dict of + Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg -> + eval arg + |> Result.andThen + (\evaluatedArg1 -> + case evaluatedArg1 of + Value.List () listItems -> + let + evaluate list res = + case list of + [] -> + Ok res + + head :: tail -> + case head of + Value.Tuple () [ key, value ] -> + case eval (Value.Apply () (Value.Apply () func key) value) of + Ok (Value.Literal _ (BoolLiteral True)) -> + evaluate tail (res ++ [ Value.Tuple () [ key, value ] ]) + + Ok (Value.Literal _ (BoolLiteral False)) -> + evaluate tail tail + + Ok other -> + Err (ExpectedBoolLiteral other) + + Err other -> + Err other + + _ -> + Err TupleExpected + in + evaluate listItems [] |> Result.map (Value.List ()) |> Result.map (fromListValue ()) + + _ -> + Err (ExpectedList evaluatedArg1) + ) + + _ -> + Err (UnexpectedArguments [ dict ]) + + _ -> + Err (UnexpectedArguments args) + ) + , ( "partition" + , \eval args -> + case args of + [ fun, dict ] -> + case dict of + Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg -> + eval arg + |> Result.andThen + (\evaluatedArg1 -> + case evaluatedArg1 of + Value.List () listItems -> + let + evaluate : List RawValue -> List RawValue -> List RawValue -> Result Error ( List RawValue, List RawValue ) + evaluate list1 list2 items = + case items of + [] -> + Ok ( list1, list2 ) + + head1 :: tail1 -> + case eval (Value.Apply () fun head1) of + Ok (Value.Literal _ (BoolLiteral True)) -> + evaluate (list1 ++ [ head1 ]) list2 tail1 + + Ok (Value.Literal _ (BoolLiteral False)) -> + evaluate list1 (list2 ++ [ head1 ]) tail1 + + Ok other -> + Err (ExpectedBoolLiteral other) + + Err other -> + Err other + in + listItems + |> evaluate [] [] + |> Result.map + (\( list1, list2 ) -> + Value.Tuple () [ Value.List () list1, Value.List () list2 ] + ) + + _ -> + Err (ExpectedList evaluatedArg1) + ) + + _ -> + Err (UnexpectedArguments [ dict ]) + + _ -> + Err (UnexpectedArguments args) + ) + + --, ("union" + -- , \eval args -> + -- case args of + -- [dict1, dict2]-> + -- case (dict1, dict2) of + -- (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg1, Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) arg2) -> + -- case (arg1, arg2) of + -- [Value.List _ list1, Value.List _ list2] -> + -- + -- _-> + -- Err (ExpectedList arg1, ExpectedList arg2) + -- _-> + -- Err (UnexpectedArguments [ dict1, dict2 ]) + -- _-> + -- Err (UnexpectedArguments args) + -- ) ] diff --git a/src/Morphir/IR/SDK/LocalDate.elm b/src/Morphir/IR/SDK/LocalDate.elm index 848b708f1..f5ae67b27 100644 --- a/src/Morphir/IR/SDK/LocalDate.elm +++ b/src/Morphir/IR/SDK/LocalDate.elm @@ -22,16 +22,15 @@ import Morphir.IR.Documented exposing (Documented) import Morphir.IR.Literal as Literal import Morphir.IR.Module as Module exposing (ModuleName) import Morphir.IR.Name as Name -import Morphir.IR.Path as Path exposing (Path) -import Morphir.IR.SDK.Basics exposing (intType) +import Morphir.IR.Path as Path +import Morphir.IR.SDK.Basics exposing (boolType, intType) import Morphir.IR.SDK.Common exposing (toFQName, vSpec) import Morphir.IR.SDK.Maybe exposing (maybeType) import Morphir.IR.SDK.String exposing (stringType) import Morphir.IR.Type exposing (Specification(..), Type(..)) +import Morphir.IR.Value as Value exposing (Value) import Morphir.SDK.LocalDate as LocalDate import Morphir.Value.Native as Native -import Morphir.IR.Value as Value -import Morphir.IR.Value exposing (Value) moduleName : ModuleName @@ -50,13 +49,53 @@ moduleSpec : Module.Specification () moduleSpec = { types = Dict.fromList - [ ( Name.fromString "LocalDate", DerivedTypeSpecification [] config |> Documented "Type that represents a date concept." ) + [ ( Name.fromString "LocalDate" + , DerivedTypeSpecification [] config + |> Documented "Type that represents a date concept." + ) + , ( Name.fromString "DayOfWeek" + , CustomTypeSpecification [] + (Dict.fromList + [ ( Name.fromString "Monday", [] ) + , ( Name.fromString "Tuesday", [] ) + , ( Name.fromString "Wednesday", [] ) + , ( Name.fromString "Thursday", [] ) + , ( Name.fromString "Friday", [] ) + , ( Name.fromString "Saturday", [] ) + , ( Name.fromString "Sunday", [] ) + ] + ) + |> Documented "Type that represents days of the week." + ) + , ( Name.fromString "Month" + , CustomTypeSpecification [] + (Dict.fromList + [ ( Name.fromString "January", [] ) + , ( Name.fromString "February", [] ) + , ( Name.fromString "March", [] ) + , ( Name.fromString "April", [] ) + , ( Name.fromString "May", [] ) + , ( Name.fromString "June", [] ) + , ( Name.fromString "July", [] ) + , ( Name.fromString "August", [] ) + , ( Name.fromString "September", [] ) + , ( Name.fromString "October", [] ) + , ( Name.fromString "November", [] ) + , ( Name.fromString "December", [] ) + ] + ) + |> Documented "Type that represents months of the year." + ) ] , values = Dict.fromList - [ vSpec "toISOString" [ ( "date", localDateType () ) ] (stringType ()) + [ vSpec "fromCalendarDate" [ ( "y", intType () ), ( "m", monthType () ), ( "d", intType () ) ] (localDateType ()) + , vSpec "toISOString" [ ( "date", localDateType () ) ] (stringType ()) , vSpec "fromISO" [ ( "iso", stringType () ) ] (maybeType () (localDateType ())) + , vSpec "fromOrdinalDate" [ ( "y", intType () ), ( "dayOfyear", intType () ) ] (localDateType ()) , vSpec "fromParts" [ ( "year", intType () ), ( "month", intType () ), ( "day", intType () ) ] (maybeType () (localDateType ())) + , vSpec "day" [ ( "localDate", localDateType () ) ] (intType ()) + , vSpec "dayOfWeek" [ ( "localDate", localDateType () ) ] (dayOfWeekType ()) , vSpec "diffInDays" [ ( "date1", localDateType () ), ( "date2", localDateType () ) ] (intType ()) , vSpec "diffInWeeks" [ ( "date1", localDateType () ), ( "date2", localDateType () ) ] (intType ()) , vSpec "diffInMonths" [ ( "date1", localDateType () ), ( "date2", localDateType () ) ] (intType ()) @@ -65,16 +104,32 @@ moduleSpec = , vSpec "addWeeks" [ ( "offset", intType () ), ( "startDate", localDateType () ) ] (localDateType ()) , vSpec "addMonths" [ ( "offset", intType () ), ( "startDate", localDateType () ) ] (localDateType ()) , vSpec "addYears" [ ( "offset", intType () ), ( "startDate", localDateType () ) ] (localDateType ()) + , vSpec "isWeekend" [ ( "localDate", localDateType () ) ] (boolType ()) + , vSpec "isWeekday" [ ( "localDate", localDateType () ) ] (boolType ()) + , vSpec "month" [ ( "localDate", localDateType () ) ] (monthType ()) + , vSpec "monthNumber" [ ( "localDate", localDateType () ) ] (intType ()) + , vSpec "monthToInt" [ ( "m", monthType () ) ] (intType ()) + , vSpec "year" [ ( "localDate", localDateType () ) ] (intType ()) ] , doc = Just "Contains the LocalDate type (representing a date concept), and it's associated functions." } +dayOfWeekType : a -> Type a +dayOfWeekType attributes = + Reference attributes (toFQName moduleName "DayOfWeek") [] + + localDateType : a -> Type a localDateType attributes = Reference attributes (toFQName moduleName "LocalDate") [] +monthType : a -> Type a +monthType attributes = + Reference attributes (toFQName moduleName "Month") [] + + nativeFunctions : List ( String, Native.Function ) nativeFunctions = [ ( "fromISO" @@ -85,6 +140,7 @@ nativeFunctions = ) ] + fromISO : a -> Value a a -> Value a a fromISO a value = - Value.Apply a (Value.Reference a ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "local", "date" ] ], [ "from", "i", "s", "o" ] )) value \ No newline at end of file + Value.Apply a (Value.Reference a ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "local", "date" ] ], [ "from", "i", "s", "o" ] )) value diff --git a/src/Morphir/IR/SDK/Maybe.elm b/src/Morphir/IR/SDK/Maybe.elm index 13bf7b125..8d97aeb00 100644 --- a/src/Morphir/IR/SDK/Maybe.elm +++ b/src/Morphir/IR/SDK/Maybe.elm @@ -20,12 +20,15 @@ module Morphir.IR.SDK.Maybe exposing (just, maybeType, moduleName, moduleSpec, n import Dict import Maybe import Morphir.IR.Documented exposing (Documented) +import Morphir.IR.Literal exposing (Literal(..)) import Morphir.IR.Module as Module exposing (ModuleName) import Morphir.IR.Name as Name exposing (Name) import Morphir.IR.Path as Path exposing (Path) +import Morphir.IR.SDK.Basics exposing (boolType) import Morphir.IR.SDK.Common exposing (tFun, tVar, toFQName, vSpec) import Morphir.IR.Type as Type exposing (Specification(..), Type(..)) import Morphir.IR.Value as Value exposing (Pattern, RawValue, Value) +import Morphir.SDK.Bool exposing (false, true) import Morphir.Value.Error exposing (Error(..)) import Morphir.Value.Native as Native exposing (decodeFun1, decodeMaybe, decodeRaw, encodeMaybeResult, encodeRaw, eval2, eval3) @@ -96,6 +99,10 @@ moduleSpec = , ( "maybe", maybeType () (tVar "a") ) ] (tVar "a") + , vSpec "hasValue" + [ ( "maybe", maybeType () (tVar "a") ) + ] + (boolType ()) ] , doc = Just "Contains the Maybe type (representing optional values), and related functions." } @@ -279,6 +286,24 @@ nativeFunctions = _ -> Err (UnexpectedArguments args) + ), + ( "hasValue" + ,\eval args -> + case args of + [ arg1 ] -> + eval arg1 + |> Result.andThen + (\evaluatedArg1 -> + case evaluatedArg1 of + Value.Apply () (Value.Constructor _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "just" ] )) _ -> + Ok ( (Value.Literal () (BoolLiteral true) ) ) + (Value.Constructor _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "nothing" ] )) -> + Ok ( (Value.Literal () (BoolLiteral false) ) ) + _ -> + Err (UnexpectedArguments args) + ) + _ -> + Err (UnexpectedArguments args) ) ] diff --git a/src/Morphir/IR/SDK/Month.elm b/src/Morphir/IR/SDK/Month.elm deleted file mode 100644 index f5f737e25..000000000 --- a/src/Morphir/IR/SDK/Month.elm +++ /dev/null @@ -1,66 +0,0 @@ -{- - Copyright 2020 Morgan Stanley - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. --} - - -module Morphir.IR.SDK.Month exposing (..) - -import Dict -import Morphir.IR.Documented exposing (Documented) -import Morphir.IR.Module as Module exposing (ModuleName) -import Morphir.IR.Name as Name -import Morphir.IR.Path as Path exposing (Path) -import Morphir.IR.SDK.Common exposing (toFQName) -import Morphir.IR.Type as Type exposing (Specification(..), Type(..)) - - -moduleName : ModuleName -moduleName = - Path.fromString "Month" - - -moduleSpec : Module.Specification () -moduleSpec = - { types = - Dict.fromList - [ ( Name.fromString "Month" - , CustomTypeSpecification [] - (Dict.fromList - [ ( Name.fromString "January", [] ) - , ( Name.fromString "February", [] ) - , ( Name.fromString "March", [] ) - , ( Name.fromString "April", [] ) - , ( Name.fromString "May", [] ) - , ( Name.fromString "June", [] ) - , ( Name.fromString "July", [] ) - , ( Name.fromString "August", [] ) - , ( Name.fromString "September", [] ) - , ( Name.fromString "October", [] ) - , ( Name.fromString "November", [] ) - , ( Name.fromString "December", [] ) - ] - ) - |> Documented "Type that represents months of the year." - ) - ] - , values = - Dict.empty - , doc = Just "Contains a type representing the months of the year." - } - - -dateType : a -> Type a -dateType attributes = - Reference attributes (toFQName moduleName "Month") [] diff --git a/src/Morphir/IR/Type.elm b/src/Morphir/IR/Type.elm index 97a32e0fe..55d85e6c5 100644 --- a/src/Morphir/IR/Type.elm +++ b/src/Morphir/IR/Type.elm @@ -23,7 +23,7 @@ module Morphir.IR.Type exposing , Definition(..), typeAliasDefinition, customTypeDefinition, definitionToSpecification, definitionToSpecificationWithPrivate , Constructors, Constructor, ConstructorArgs , mapTypeAttributes, mapSpecificationAttributes, mapDefinitionAttributes, mapDefinition, typeAttributes - , eraseAttributes, collectVariables, collectReferences, collectReferencesFromDefintion, substituteTypeVariables, toString + , eraseAttributes, collectVariables, collectReferences, collectReferencesFromDefintion, substituteTypeVariables, toString, DerivedTypeSpecificationDetails ) {-| Like any other programming languages Morphir has a type system as well. This module defines the building blocks of @@ -109,7 +109,7 @@ Here is the full definition for reference: # Specification -@docs Specification, typeAliasSpecification, opaqueTypeSpecification, customTypeSpecification +@docs Specification, typeAliasSpecification, opaqueTypeSpecification, customTypeSpecification, DerivedTypeSpecificationDetails # Definition @@ -240,7 +240,8 @@ type Specification a | CustomTypeSpecification (List Name) (Constructors a) | DerivedTypeSpecification (List Name) (DerivedTypeSpecificationDetails a) - +{-| Details of the base type of a Derived Type +-} type alias DerivedTypeSpecificationDetails a = { baseType : Type a , fromBaseType : FQName diff --git a/src/Morphir/JsonSchema/Backend.elm b/src/Morphir/JsonSchema/Backend.elm index fd5dbd5da..398102f6d 100644 --- a/src/Morphir/JsonSchema/Backend.elm +++ b/src/Morphir/JsonSchema/Backend.elm @@ -211,7 +211,7 @@ mapType qName typ = ( "Morphir.SDK:LocalTime:localTime", [] ) -> Ok (String (StringConstraints (Just "time"))) - ( "Morphir.SDK:Month:month", [] ) -> + ( "Morphir.SDK:LocalDate:month", [] ) -> Ok (OneOf [ Const "January" diff --git a/src/Morphir/SDK/LocalDate.elm b/src/Morphir/SDK/LocalDate.elm index 3a66edad3..32baf1ef4 100644 --- a/src/Morphir/SDK/LocalDate.elm +++ b/src/Morphir/SDK/LocalDate.elm @@ -19,7 +19,11 @@ module Morphir.SDK.LocalDate exposing ( LocalDate , diffInDays, diffInWeeks, diffInMonths, diffInYears , addDays, addWeeks, addMonths, addYears - , toISOString, fromISO, fromParts + , fromCalendarDate, fromISO, fromOrdinalDate, fromParts + , toISOString, monthToInt + , DayOfWeek(..), dayOfWeek, isWeekend, isWeekday + , Month(..) + , year, month, monthNumber, day ) {-| This module adds the definition of a date without time zones. Useful in business modeling. @@ -38,11 +42,24 @@ module Morphir.SDK.LocalDate exposing # Constructors -@docs toISOString, fromISO, fromParts +@docs fromCalendarDate, fromISO, fromOrdinalDate, fromParts + + +# Convert + +@docs toISOString, monthToInt + + +# Query + +@docs DayOfWeek, dayOfWeek, isWeekend, isWeekday +@docs Month +@docs year, month, monthNumber, day -} import Date exposing (Date, Unit(..)) +import Time {-| Concept of a date without time zones. @@ -107,6 +124,36 @@ addYears count date = Date.add Years count date +{-| Create a date from a [calendar date][gregorian]: a year, month, and day of +the month. Out-of-range day values will be clamped. + + import Morphir.SDK.LocalDate exposing (fromCalendarDate, Month(..)) + + fromCalendarDate 2018 September 26 + +[gregorian]: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar + +-} +fromCalendarDate : Int -> Month -> Int -> LocalDate +fromCalendarDate y m d = + Date.fromCalendarDate y (monthToMonth m) d + + +{-| Create a date from an [ordinal date][ordinaldate]: a year and day of the +year. Out-of-range day values will be clamped. + + import Morphir.SDK.LocalDate exposing (fromOrdinalDate) + + fromOrdinalDate 2018 269 + +[ordinaldate]: https://en.wikipedia.org/wiki/Ordinal_date + +-} +fromOrdinalDate : Int -> Int -> LocalDate +fromOrdinalDate y dayOfYear = + Date.fromOrdinalDate y dayOfYear + + {-| Construct a LocalDate based on ISO formatted string. Opportunity for error denoted by Maybe return type. -} fromISO : String -> Maybe LocalDate @@ -126,14 +173,14 @@ Errors can occur when any of the given values fall outside of their relevant con For example, the date given as 2000 2 30 (2000-Feb-30) would fail because the day of the 30th is impossible. -} fromParts : Int -> Int -> Int -> Maybe LocalDate -fromParts year month day = +fromParts yearNumber monthNum dayOfMonthNumber = -- We do all of this processing because our Elm Date library accepts invalid values while most other languages don't. -- So we want to maintain consistency. -- Oddly, Date has fromCalendarParts, but it's not exposed. let maybeMonth = - if month > 0 && month < 13 then - Just (Date.numberToMonth month) + if monthNum > 0 && monthNum < 13 then + Just (Date.numberToMonth monthNum) else Nothing @@ -141,14 +188,272 @@ fromParts year month day = maybeMonth |> Maybe.map (\m -> - ( m, Date.fromCalendarDate year m day ) + ( m, Date.fromCalendarDate yearNumber m dayOfMonthNumber ) ) |> Maybe.map (\( dateMonth, date ) -> - if Date.year date == year && Date.month date == dateMonth && Date.day date == day then + if Date.year date == yearNumber && Date.month date == dateMonth && Date.day date == dayOfMonthNumber then Just date else Nothing ) |> Maybe.withDefault Nothing + + +{-| Returns the year as a number. +-} +year : LocalDate -> Int +year localDate = + Date.year localDate + + +{-| Returns the month of the year for a given date. +-} +month : LocalDate -> Month +month localDate = + case Date.month localDate of + Time.Jan -> + January + + Time.Feb -> + February + + Time.Mar -> + March + + Time.Apr -> + April + + Time.May -> + May + + Time.Jun -> + June + + Time.Jul -> + July + + Time.Aug -> + August + + Time.Sep -> + September + + Time.Oct -> + October + + Time.Nov -> + November + + Time.Dec -> + December + + +{-| Returns the month of the year as an Int, where January is month 1 and December is month 12. +-} +monthNumber : LocalDate -> Int +monthNumber localDate = + case Date.month localDate of + Time.Jan -> + 1 + + Time.Feb -> + 2 + + Time.Mar -> + 3 + + Time.Apr -> + 4 + + Time.May -> + 5 + + Time.Jun -> + 6 + + Time.Jul -> + 7 + + Time.Aug -> + 8 + + Time.Sep -> + 9 + + Time.Oct -> + 10 + + Time.Nov -> + 11 + + Time.Dec -> + 12 + + +{-| Converts a Month to an Int, where January is month 1 and December is month 12. +-} +monthToInt : Month -> Int +monthToInt m = + case m of + January -> + 1 + + February -> + 2 + + March -> + 3 + + April -> + 4 + + May -> + 5 + + June -> + 6 + + July -> + 7 + + August -> + 8 + + September -> + 9 + + October -> + 10 + + November -> + 11 + + December -> + 12 + + +monthToMonth : Month -> Time.Month +monthToMonth m = + case m of + January -> + Time.Jan + + February -> + Time.Feb + + March -> + Time.Mar + + April -> + Time.Apr + + May -> + Time.May + + June -> + Time.Jun + + July -> + Time.Jul + + August -> + Time.Aug + + September -> + Time.Sep + + October -> + Time.Oct + + November -> + Time.Nov + + December -> + Time.Dec + + +{-| The day of the month (1–31). +-} +day : LocalDate -> Int +day localDate = + Date.day localDate + + +{-| Returns the day of week for a date. +-} +dayOfWeek : LocalDate -> DayOfWeek +dayOfWeek localDate = + case Date.weekday localDate of + Time.Mon -> + Monday + + Time.Tue -> + Tuesday + + Time.Wed -> + Wednesday + + Time.Thu -> + Thursday + + Time.Fri -> + Friday + + Time.Sat -> + Saturday + + Time.Sun -> + Sunday + + +{-| Returns true if the date falls on a weekend (Saturday or Sunday). +-} +isWeekend : LocalDate -> Bool +isWeekend localDate = + case dayOfWeek localDate of + Saturday -> + True + + Sunday -> + True + + _ -> + False + + +{-| Returns true if the date falls on a weekday (any day other than Saturday or Sunday). +-} +isWeekday : LocalDate -> Bool +isWeekday localDate = + not (isWeekend localDate) + + +{-| Type that represents a day of the week. +-} +type DayOfWeek + = Monday + | Tuesday + | Wednesday + | Thursday + | Friday + | Saturday + | Sunday + + +{-| Gregorian calendar months in English. +-} +type Month + = January + | February + | March + | April + | May + | June + | July + | August + | September + | October + | November + | December diff --git a/src/Morphir/SDK/Maybe.elm b/src/Morphir/SDK/Maybe.elm new file mode 100644 index 000000000..c57158e11 --- /dev/null +++ b/src/Morphir/SDK/Maybe.elm @@ -0,0 +1,124 @@ +module Morphir.SDK.Maybe exposing (..) + +{-| This library fills a bunch of important niches in Elm. A `Maybe` can help +you with optional arguments, error handling, and records with optional fields. + +# Definition +@docs Maybe + +# Common Helpers +@docs withDefault, map, map2, map3, map4, map5 + +# Chaining Maybes +@docs andThen +-} + +{-| Provide a default value, turning an optional value into a normal +value. This comes in handy when paired with functions like +[`Dict.get`](Dict#get) which gives back a `Maybe`. + + withDefault 100 (Just 42) -- 42 + withDefault 100 Nothing -- 100 + + withDefault "unknown" (Dict.get "Tom" Dict.empty) -- "unknown" + +**Note:** This can be overused! Many cases are better handled by a `case` +expression. And if you end up using `withDefault` a lot, it can be a good sign +that a [custom type][ct] will clean your code up quite a bit! + +[ct]: https://guide.elm-lang.org/types/custom_types.html +-} +withDefault : a -> Maybe a -> a +withDefault default maybe = + Maybe.withDefault default maybe + +{-| Transform a `Maybe` value with a given function: + + map sqrt (Just 9) == Just 3 + map sqrt Nothing == Nothing + + map sqrt (String.toFloat "9") == Just 3 + map sqrt (String.toFloat "x") == Nothing + +-} +map : (a -> b) -> Maybe a -> Maybe b +map = + Maybe.map + +{-| Apply a function if all the arguments are `Just` a value. + + map2 (+) (Just 3) (Just 4) == Just 7 + map2 (+) (Just 3) Nothing == Nothing + map2 (+) Nothing (Just 4) == Nothing + + map2 (+) (String.toInt "1") (String.toInt "123") == Just 124 + map2 (+) (String.toInt "x") (String.toInt "123") == Nothing + map2 (+) (String.toInt "1") (String.toInt "1.3") == Nothing +-} +map2 : (a -> b -> value) -> Maybe a -> Maybe b -> Maybe value +map2 = + Maybe.map2 + +{-|-} +map3 : (a -> b -> c -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe value +map3 = + Maybe.map3 + +{-|-} +map4 : (a -> b -> c -> d -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe value +map4 = + Maybe.map4 + +{-|-} +map5 : (a -> b -> c -> d -> e -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe e -> Maybe value +map5 = + Maybe.map5 + +{-| Chain together many computations that may fail. It is helpful to see its +definition: + + andThen : (a -> Maybe b) -> Maybe a -> Maybe b + andThen callback maybe = + case maybe of + Just value -> + callback value + + Nothing -> + Nothing + +This means we only continue with the callback if things are going well. For +example, say you need to parse some user input as a month: + + parseMonth : String -> Maybe Int + parseMonth userInput = + String.toInt userInput + |> andThen toValidMonth + + toValidMonth : Int -> Maybe Int + toValidMonth month = + if 1 <= month && month <= 12 then + Just month + else + Nothing + +In the `parseMonth` function, if `String.toInt` produces `Nothing` (because +the `userInput` was not an integer) this entire chain of operations will +short-circuit and result in `Nothing`. If `toValidMonth` results in `Nothing`, +again the chain of computations will result in `Nothing`. +-} +andThen : (a -> Maybe b) -> Maybe a -> Maybe b +andThen = + Maybe.andThen + +{-| Check whether a Maybe has a value in it or not + hasValue: Maybe a -> Bool +-} +hasValue : Maybe a -> Bool +hasValue maybe = + case maybe of + Just _ -> + True + Nothing -> + False + + diff --git a/src/Morphir/SDK/Month.elm b/src/Morphir/SDK/Month.elm deleted file mode 100644 index 01182333d..000000000 --- a/src/Morphir/SDK/Month.elm +++ /dev/null @@ -1,37 +0,0 @@ -{- -Copyright 2020 Morgan Stanley - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. --} - -module Morphir.SDK.Month exposing (Month) - -{-| This module adds the definition of a month concept for business modeling. -@docs Month --} - -{-| Gregorian calendar months in English. --} -type Month - = January - | February - | March - | April - | May - | June - | July - | August - | September - | October - | November - | December diff --git a/src/Morphir/SDK/String.elm b/src/Morphir/SDK/String.elm index 290f93623..b78f7f806 100644 --- a/src/Morphir/SDK/String.elm +++ b/src/Morphir/SDK/String.elm @@ -77,3 +77,17 @@ ofMaxLength maxLength ctor value = else Nothing + +{-| Checks to see if two strings are equal ignore case + + isEqual = + String.equalIgnoreCase "HeLlO" "Hello" + + isEqual == True +-} +equalIgnoreCase : String -> String -> Bool +equalIgnoreCase str1 str2 = + if not ((String.length str1) == (String.length str2)) then + False + else + (String.toLower str1) == (String.toLower str2) diff --git a/src/Morphir/Scala/AST.elm b/src/Morphir/Scala/AST.elm index 948a0465e..03fe7eea1 100644 --- a/src/Morphir/Scala/AST.elm +++ b/src/Morphir/Scala/AST.elm @@ -17,7 +17,7 @@ module Morphir.Scala.AST exposing ( Name, Path, Documented, Annotated, withAnnotation, withoutAnnotation, CompilationUnit, PackageDecl - , ImportDecl, ImportName, Mod(..), TypeDecl(..), ArgDecl, ArgValue(..), MemberDecl(..) + , ImportDecl, ImportName(..), Mod(..), TypeDecl(..), ArgDecl, ArgValue(..), MemberDecl(..) , Type(..), Value(..), Pattern(..), Lit(..), Generator(..) , nameOfTypeDecl ) @@ -256,6 +256,8 @@ type Value | CommentedValue Value String | ForComp (List Generator) Value | TypeAscripted Value Type + | New Path Name (List ArgValue) + | Throw Value {-| -} @@ -286,6 +288,7 @@ type Lit | IntegerLit Int | FloatLit Float | DecimalLit Decimal + | NullLit {-| -} diff --git a/src/Morphir/Scala/PrettyPrinter.elm b/src/Morphir/Scala/PrettyPrinter.elm index b0412987b..52894c638 100644 --- a/src/Morphir/Scala/PrettyPrinter.elm +++ b/src/Morphir/Scala/PrettyPrinter.elm @@ -72,11 +72,29 @@ mapCompilationUnit opt cu = concat [ concat [ "package ", dotSep (prefixKeywords cu.packageDecl), newLine ] , newLine + , mapImports cu.imports , cu.typeDecls |> List.map (mapDocumented (mapAnnotated (mapTypeDecl opt))) |> String.join (newLine ++ newLine) ] +mapImports : List ImportDecl -> Doc +mapImports imports = + case imports of + [] -> + "" + importsList -> + (importsList |> List.map mapImport) ++ [ newLine ] + |> concat + + +mapImport : ImportDecl -> Doc +mapImport importDecl = + concat + [ "import " + , String.join "." (importDecl.packagePrefix) + , newLine + ] mapTypeDecl : Options -> TypeDecl -> Doc mapTypeDecl opt typeDecl = @@ -437,6 +455,9 @@ mapValue opt value = Apply funValue argValues -> mapValue opt funValue ++ argValueBlock opt argValues + + New path name argValues -> + "new" ++ " " ++ (dotSep <| prefixKeywords (path ++ [ name ])) ++ argValueBlock opt argValues UnOp op right -> op ++ mapValue opt right @@ -577,6 +598,8 @@ mapValue opt value = , mapType opt tpe , ")" ] + Throw exceptionExpr -> + "throw " ++ (mapValue opt exceptionExpr) mapPattern : Pattern -> Doc @@ -654,6 +677,9 @@ mapLit lit = DecimalLit decimal -> Decimal.toString decimal + NullLit -> + "null" + statementBlock : Options -> List String -> Doc statementBlock opt statements = diff --git a/src/Morphir/Snowpark/AccessElementMapping.elm b/src/Morphir/Snowpark/AccessElementMapping.elm new file mode 100644 index 000000000..030f098d1 --- /dev/null +++ b/src/Morphir/Snowpark/AccessElementMapping.elm @@ -0,0 +1,171 @@ +module Morphir.Snowpark.AccessElementMapping exposing + ( mapConstructorAccess + , mapFieldAccess + , mapReferenceAccess + , mapVariableAccess + ) + +{-| This module contains functions to generate code like `a.b` or `a`. +| +-} + +import Dict +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal exposing (Literal(..)) +import Morphir.IR.Name as Name +import Morphir.IR.Type as IrType +import Morphir.IR.Value as Value exposing (TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants exposing (MapValueType, ValueGenerationResult, applySnowparkFunc) +import Morphir.Snowpark.MappingContext + exposing + ( ValueMappingContext + , getReplacementForIdentifier + , isAnonymousRecordWithSimpleTypes + , isDataFrameFriendlyType + , isListOfDataFrameFriendlyType + , isLocalFunctionName + , isUnionTypeWithParams + , isUnionTypeWithoutParams + ) +import Morphir.Snowpark.ReferenceUtils + exposing + ( errorValueAndIssue + , isValueReferenceToSimpleTypesRecord + , scalaPathToModule + , scalaReferenceToUnionTypeCase + ) + + +checkForDataFrameVariableReference : Value ta (IrType.Type ()) -> ValueMappingContext -> Maybe String +checkForDataFrameVariableReference value ctx = + case Value.valueAttribute value of + IrType.Reference _ typeName _ -> + Dict.get typeName ctx.dataFrameColumnsObjects + + _ -> + Nothing + + +mapFieldAccess : va -> TypedValue -> Name.Name -> ValueMappingContext -> MapValueType -> ValueGenerationResult +mapFieldAccess _ value name ctx mapValue = + let + simpleFieldName = + name |> Name.toCamelCase + + valueIsFunctionParameter = + case value of + Value.Variable _ varName -> + if List.member varName ctx.parameters then + Just <| Name.toCamelCase varName + + else + Nothing + + _ -> + Nothing + + valueIsDataFrameColumnAccess = + case ( value, checkForDataFrameVariableReference value ctx ) of + ( Value.Variable _ _, Just replacement ) -> + Just replacement + + _ -> + Nothing + in + case ( isValueReferenceToSimpleTypesRecord value ctx.typesContextInfo, valueIsFunctionParameter, valueIsDataFrameColumnAccess ) of + ( _, Just replacement, _ ) -> + ( Scala.Ref [ replacement ] simpleFieldName, [] ) + + ( _, _, Just replacement ) -> + ( Scala.Ref [ replacement ] simpleFieldName, [] ) + + ( Just ( path, refererName ), Nothing, Nothing ) -> + ( Scala.Ref (path ++ [ refererName |> Name.toTitleCase ]) simpleFieldName, [] ) + + _ -> + if isAnonymousRecordWithSimpleTypes (value |> Value.valueAttribute) ctx.typesContextInfo then + ( applySnowparkFunc "col" [ Scala.Literal (Scala.StringLit (Name.toCamelCase name)) ], [] ) + + else + let + ( mappedValue, issues ) = + mapValue value ctx + in + ( Scala.Select mappedValue (Name.toCamelCase name), issues ) + + +mapVariableAccess : Name.Name -> TypedValue -> ValueMappingContext -> ValueGenerationResult +mapVariableAccess name nameAccess ctx = + case ( getReplacementForIdentifier name ctx, checkForDataFrameVariableReference nameAccess ctx ) of + ( Just replacement, _ ) -> + ( replacement, [] ) + + ( _, Just replacementStr ) -> + ( Scala.Variable replacementStr, [] ) + + _ -> + ( Scala.Variable (name |> Name.toCamelCase), [] ) + + +mapConstructorAccess : IrType.Type a -> FQName.FQName -> ValueMappingContext -> ValueGenerationResult +mapConstructorAccess tpe name ctx = + case ( tpe, name ) of + ( IrType.Reference _ _ _, ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "nothing" ] ) ) -> + ( applySnowparkFunc "lit" [ Scala.Literal Scala.NullLit ], [] ) + + ( IrType.Reference _ typeName _, _ ) -> + if isUnionTypeWithoutParams typeName ctx.typesContextInfo then + ( scalaReferenceToUnionTypeCase typeName name, [] ) + + else if isUnionTypeWithParams typeName ctx.typesContextInfo then + ( applySnowparkFunc "object_construct" + [ applySnowparkFunc "lit" [ Scala.Literal <| Scala.StringLit "__tag" ] + , applySnowparkFunc "lit" [ Scala.Literal <| Scala.StringLit (name |> FQName.getLocalName |> Name.toTitleCase) ] + ] + , [] + ) + + else + errorValueAndIssue <| "Constructor access not converted" ++ FQName.toString name + + _ -> + errorValueAndIssue <| "Constructor access not converted" ++ FQName.toString name + + +mapReferenceAccess : IrType.Type () -> FQName.FQName -> MapValueType -> ValueMappingContext -> ValueGenerationResult +mapReferenceAccess tpe name mapValue ctx = + if Dict.member name ctx.globalValuesToInline then + let + inlinedResult = + ctx.globalValuesToInline + |> Dict.get name + |> Maybe.map (\definition -> mapValue definition.body ctx) + |> Maybe.withDefault ( Scala.Wildcard, [] ) + in + inlinedResult + + else if + isDataFrameFriendlyType tpe ctx.typesContextInfo + || isListOfDataFrameFriendlyType tpe ctx.typesContextInfo + then + let + nsName = + scalaPathToModule name + + containerObjectFieldName = + FQName.getLocalName name |> Name.toCamelCase + in + ( Scala.Ref nsName containerObjectFieldName, [] ) + + else + case tpe of + IrType.Function _ _ _ -> + if isLocalFunctionName name ctx then + ( Scala.Ref (scalaPathToModule name) (name |> FQName.getLocalName |> Name.toCamelCase), [] ) + + else + errorValueAndIssue ("Reference access to function not converted" ++ FQName.toString name) + + _ -> + errorValueAndIssue ("Reference access not converted: " ++ FQName.toString name) diff --git a/src/Morphir/Snowpark/AggregateMapping.elm b/src/Morphir/Snowpark/AggregateMapping.elm new file mode 100644 index 000000000..8ea454b4c --- /dev/null +++ b/src/Morphir/Snowpark/AggregateMapping.elm @@ -0,0 +1,242 @@ +module Morphir.Snowpark.AggregateMapping exposing (processAggregateLambdaBody) + +import Dict +import Morphir.IR.Name as Name +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value as ValueIR exposing (TypedValue) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants as Constants +import Morphir.Snowpark.MappingContext exposing (ValueMappingContext, getFieldInfoIfRecordType) +import Morphir.Snowpark.Operatorsmaps as Operatorsmaps + + +processAggregateLambdaBody : Constants.LambdaInfo () -> Constants.MappingFunc -> { columnNameList : List Scala.Value, variable : List Scala.ArgValue } +processAggregateLambdaBody lambdaInfo ( mapValue, ctx ) = + case lambdaInfo.lambdaBody of + ValueIR.Record fieldListType _ -> + case lambdaInfo.lambdaPattern of + ValueIR.AsPattern functionToApply _ functionName -> + let + recordFieldsName = + getFieldInfoIfRecordType fieldListType ctx.typesContextInfo |> Maybe.map (List.map Tuple.first) |> aliasMap + in + { columnNameList = recordFieldsName + , variable = processRecords lambdaInfo functionToApply functionName ( mapValue, ctx ) recordFieldsName + } + + _ -> + { columnNameList = [] + , variable = [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "To Do - Processing Record")) ] + } + + ValueIR.Apply _ x ((ValueIR.Apply _ _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], _ )) (ValueIR.FieldFunction _ _))) as y) -> + variablesFromAggregate (ValueIR.uncurryApply x y) ( mapValue, ctx ) + |> (\variableInfo -> { columnNameList = variableInfo.aliasName, variable = concatFunctions variableInfo.variables }) + + _ -> + { columnNameList = [] + , variable = [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "To Do - Processing Other")) ] + } + + +processRecords : Constants.LambdaInfo () -> TypeIR.Type () -> Name.Name -> Constants.MappingFunc -> List Scala.Value -> List Scala.ArgValue +processRecords lambdaInfo functionToApply functionName mappingFunc columnNameList = + case lambdaInfo.lambdaBody of + ValueIR.Record _ dictVariables -> + let + variablesInfo = + Dict.toList dictVariables + |> List.map (processRecordsVariables lambdaInfo mappingFunc functionToApply functionName) + + variables = + List.map2 processColumnList variablesInfo columnNameList + in + variables |> List.filterMap (\x -> x) |> List.map generateFunctionFromColumnRecords + + _ -> + [ Scala.ArgValue Nothing (defaultValueForUnsupportedElement "Unsupported Record") ] + + +generateFunctionFromColumnRecords : ( String, Scala.Value, Scala.Value ) -> Scala.ArgValue +generateFunctionFromColumnRecords ( funcName, columnName, aliasValue ) = + if String.contains "Unsupported" funcName then + Scala.ArgValue Nothing <| defaultValueForUnsupportedElement "Unsupported column" + + else + Constants.applySnowparkFunc funcName [ columnName ] |> joinWithAlias aliasValue + + +processColumnList : Maybe ( String, Scala.Value, Name.Name ) -> Scala.Value -> Maybe ( String, Scala.Value, Scala.Value ) +processColumnList variable aliasName = + case variable of + Just ( funcName, value, _ ) -> + Just ( funcName, value, aliasName ) + + _ -> + Nothing + + +processRecordsVariables : Constants.LambdaInfo ta -> Constants.MappingFunc -> TypeIR.Type () -> Name.Name -> ( Name.Name, TypedValue ) -> Maybe ( String, Scala.Value, Name.Name ) +processRecordsVariables lambdaInfo ( mapValue, ctx ) functionFromLambda functionFromLamnbdaName ( key, value ) = + case value of + ValueIR.Apply _ (ValueIR.Variable functionType functionName) variableToProcess -> + if functionType == functionFromLambda && functionFromLamnbdaName == functionName then + getFunctionVariable variableToProcess ( mapValue, ctx ) lambdaInfo + + else + Just ( "Unsupported case", Scala.Literal (Scala.StringLit (Name.toCamelCase key)), [] ) + + ValueIR.Variable _ name -> + if name == lambdaInfo.firstParameter then + if key /= lambdaInfo.groupByName then + Just ( "col", Scala.Literal (Scala.StringLit (Name.toCamelCase lambdaInfo.groupByName)), key ) + + else + Nothing + + else + Just <| ( "Unsupported variable", Scala.Literal (Scala.StringLit ("UnSupported variable for " ++ Name.toCamelCase name)), [ "Unsupported" ] ) + + _ -> + Just <| ( "Unsupported field", defaultValueForUnsupportedElement "Unsupported field from Record", [ "Unsupported field" ] ) + + +getFunctionVariable : TypedValue -> Constants.MappingFunc -> Constants.LambdaInfo ta -> Maybe ( String, Scala.Value, Name.Name ) +getFunctionVariable variableInfo mappingFunc lambdaInfo = + case variableInfo of + ValueIR.Apply _ _ _ -> + getVariable variableInfo mappingFunc + + ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], [ "count" ] ) -> + Just ( "count", Constants.applySnowparkFunc "col" [ Scala.Literal (Scala.StringLit (Name.toCamelCase lambdaInfo.groupByName)) ], [ "count" ] ) + + _ -> + Just ( "Unsupported", defaultValueForUnsupportedElement "Unsupported Reference", [] ) + + +concatFunctions : Constants.VariableInformation -> List Scala.ArgValue +concatFunctions ( aliasList, functions ) = + functions + |> List.map processList + |> List.map2 joinWithAlias (List.tail aliasList |> Maybe.withDefault []) + + +processList : ( String, Scala.Value ) -> Scala.Value +processList ( funcName, columnName ) = + Constants.applySnowparkFunc funcName [ columnName ] + + +variablesFromAggregate : ( TypedValue, List TypedValue ) -> Constants.MappingFunc -> Constants.AliasVariableInfo +variablesFromAggregate body ( mapValue, ctx ) = + case body of + ( ValueIR.Constructor tpe _, array ) -> + let + aliasApplies = + aliasMap <| getFieldsFromType tpe ctx + + variablesFromApply = + array + |> List.map (getVariablesFromApply ( mapValue, ctx )) + |> List.filterMap (\x -> x) + in + joinAliasInfo aliasApplies variablesFromApply |> (\x -> { aliasName = aliasApplies, variables = x }) + + _ -> + { aliasName = [] + , variables = ( [], [ ( "Error", Scala.Literal (Scala.StringLit "To Do - Not Support in variablesFromApply") ) ] ) + } + + +joinAliasInfo : a -> b -> ( a, b ) +joinAliasInfo aliasList variableList = + ( aliasList, variableList ) + + +getFieldsFromType : TypeIR.Type () -> ValueMappingContext -> Maybe (List Name.Name) +getFieldsFromType tpe ctx = + case tpe of + TypeIR.Function _ _ ftpe -> + getFieldsFromType ftpe ctx + + _ -> + getFieldInfoIfRecordType tpe ctx.typesContextInfo + |> Maybe.map (List.map Tuple.first) + + +aliasMap : Maybe (List Name.Name) -> List Scala.Value +aliasMap fields = + case fields of + Just list -> + list + |> List.map convertNameToApply + + Nothing -> + [] + + +convertNameToApply : Name.Name -> Scala.Value +convertNameToApply name = + Scala.Literal (Scala.StringLit (Name.toCamelCase name)) + + +joinWithAlias : Scala.Value -> Scala.Value -> Scala.ArgValue +joinWithAlias aliasApply columnsApply = + let + columnAlias = + Scala.Select columnsApply "alias" + in + Scala.ArgValue Nothing (Scala.Apply columnAlias [ Scala.ArgValue Nothing aliasApply ]) + + +getVariablesFromApply : Constants.MappingFunc -> TypedValue -> Maybe ( String, Scala.Value ) +getVariablesFromApply mappingFunc value = + case value of + ValueIR.Apply _ _ property -> + let + info = + getVariable property mappingFunc + in + case info of + Just ( funcName, scalaValue, _ ) -> + Just ( funcName, scalaValue ) + + _ -> + Nothing + + _ -> + Nothing + + +getVariable : TypedValue -> Constants.MappingFunc -> Maybe ( String, Scala.Value, Name.Name ) +getVariable value ( mapValue, ctx ) = + case value of + ValueIR.Apply _ (ValueIR.Reference _ ( _, _, name )) property -> + let + func = + Operatorsmaps.mapOperator name + + ( column, _ ) = + mapValue property ctx + + columnName = + getColumnName property + in + Just ( func, column, columnName ) + + _ -> + Just ( "Unsupported", defaultValueForUnsupportedElement "Unsupported Reference", [] ) + + +defaultValueForUnsupportedElement : String -> Scala.Value +defaultValueForUnsupportedElement description = + Scala.Throw (Scala.New [] "Exception" [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit description)) ]) + + +getColumnName : TypedValue -> Name.Name +getColumnName property = + case property of + ValueIR.FieldFunction _ name -> + name + + _ -> + [] diff --git a/src/Morphir/Snowpark/Backend.elm b/src/Morphir/Snowpark/Backend.elm new file mode 100644 index 000000000..59b9f0ccd --- /dev/null +++ b/src/Morphir/Snowpark/Backend.elm @@ -0,0 +1,376 @@ +module Morphir.Snowpark.Backend exposing (Options, decodeOptions, mapDistribution, mapFunctionDefinition) + +import Dict +import Json.Decode as Decode exposing (Decoder) +import List +import List.Extra +import Morphir.File.FileMap exposing (FileMap) +import Morphir.IR.AccessControlled exposing (Access(..), AccessControlled) +import Morphir.IR.Decoration.Codec exposing (decodeNodeIDByValuePairs) +import Morphir.IR.Distribution as Distribution exposing (..) +import Morphir.IR.Documented exposing (Documented) +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal exposing (Literal(..)) +import Morphir.IR.Module as Module +import Morphir.IR.Name as Name +import Morphir.IR.NodeId exposing (NodeID) +import Morphir.IR.Package as Package +import Morphir.IR.Path as Path exposing (Path) +import Morphir.IR.Type as Type exposing (Type) +import Morphir.IR.Value as Value exposing (Pattern(..), Value(..)) +import Morphir.SDK.Dict as SDKDict +import Morphir.Scala.AST as Scala +import Morphir.Scala.Common exposing (javaObjectMethods, mapValueName, scalaKeywords) +import Morphir.Scala.PrettyPrinter as PrettyPrinter +import Morphir.Snowpark.Constants exposing (typeRefForSnowparkType) +import Morphir.Snowpark.Customization + exposing + ( CustomizationOptions + , emptyCustomizationOptions + , loadCustomizationOptions + , tryToApplyPostConversionCustomization + ) +import Morphir.Snowpark.FunctionMappingsForPlainScala as FunctionMappingsForPlainScala +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue, GenerationIssues, createGenerationReport) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext as MappingContext + exposing + ( FunctionClassification(..) + , GlobalDefinitionInformation + , MappingContextInfo + , ValueMappingContext + , emptyValueMappingContext + , getFunctionClassification + , isCandidateForDataFrame + ) +import Morphir.Snowpark.RecordWrapperGenerator as RecordWrapperGenerator +import Morphir.Snowpark.ReferenceUtils exposing (isTypeReferenceToSimpleTypesRecord) +import Morphir.Snowpark.TypeRefMapping exposing (mapFunctionReturnType, mapTypeReference) +import Set as Set + + +{-| Generate Scala files that use the Snowpark API to process DataFrame-like structures. +-} +type alias Options = + { decorations : Maybe (SDKDict.Dict NodeID Decode.Value) } + + +decodeOptions : Decoder Options +decodeOptions = + Decode.map Options + (Decode.maybe + (Decode.field "decorationsObj" decodeNodeIDByValuePairs) + ) + + +mapDistribution : Options -> Distribution -> FileMap +mapDistribution opts distro = + let + loadedOpts : CustomizationOptions + loadedOpts = + opts.decorations + |> Maybe.map loadCustomizationOptions + |> Maybe.withDefault emptyCustomizationOptions + in + case distro of + Distribution.Library packageName _ packageDef -> + mapPackageDefinition distro packageName packageDef loadedOpts + + +mapPackageDefinition : Distribution -> Package.PackageName -> Package.Definition () (Type ()) -> CustomizationOptions -> FileMap +mapPackageDefinition _ packagePath packageDef customizationOptions = + let + contextInfo = + MappingContext.processDistributionModules packagePath packageDef customizationOptions + + ( generatedScala, issuesCollections ) = + packageDef.modules + |> Dict.toList + |> List.concatMap + (\( modulePath, moduleImpl ) -> + mapModuleDefinition packagePath modulePath moduleImpl contextInfo customizationOptions + ) + |> List.unzip + + generatedFiles = + generatedScala + |> List.map + (\compilationUnit -> + let + fileContent = + compilationUnit + |> PrettyPrinter.mapCompilationUnit (PrettyPrinter.Options 2 80) + in + ( ( compilationUnit.dirPath, compilationUnit.fileName ), fileContent ) + ) + |> Dict.fromList + + issues = + issuesCollections + |> List.foldr Dict.union Dict.empty + in + Dict.insert ( [], "GenerationReport.md" ) (createGenerationReport contextInfo customizationOptions issues) generatedFiles + + +mapModuleDefinition : + Package.PackageName + -> Path + -> AccessControlled (Module.Definition () (Type ())) + -> GlobalDefinitionInformation () + -> CustomizationOptions + -> List ( Scala.CompilationUnit, GenerationIssues ) +mapModuleDefinition currentPackagePath currentModulePath accessControlledModuleDef ctxInfo customizationOptions = + let + ( scalaPackagePath, moduleName ) = + case currentModulePath |> List.reverse of + [] -> + ( [], [] ) + + lastName :: reverseModulePath -> + let + parts = + List.append currentPackagePath (List.reverse reverseModulePath) + in + ( parts |> List.map (Name.toCamelCase >> String.toLower), lastName ) + + moduleTypeDefinitions : List (Scala.Annotated Scala.MemberDecl) + moduleTypeDefinitions = + accessControlledModuleDef.value.types + |> RecordWrapperGenerator.generateRecordWrappers currentPackagePath currentModulePath ctxInfo + |> List.map (\doc -> { annotations = doc.value.annotations, value = Scala.MemberTypeDecl doc.value.value }) + + ( functionMembers, generatedImports, membersIssues ) = + accessControlledModuleDef.value.values + |> Dict.toList + |> List.map + (\( valueName, accessControlledValueDef ) -> + processFunctionMember valueName accessControlledValueDef currentPackagePath currentModulePath ctxInfo customizationOptions + ) + |> (\res -> + ( res |> List.map (\( t, _, _ ) -> t) |> List.concat |> List.map Scala.withoutAnnotation + , res |> List.map (\( _, t, _ ) -> t) |> List.concat + , res |> List.map (\( _, _, t ) -> t) |> List.foldr Dict.union Dict.empty + ) + ) + + moduleUnit : Scala.CompilationUnit + moduleUnit = + { dirPath = scalaPackagePath + , fileName = (moduleName |> Name.toTitleCase) ++ ".scala" + , packageDecl = scalaPackagePath + , imports = generatedImports |> List.Extra.uniqueBy .packagePrefix + , typeDecls = + [ Scala.Documented (Just (String.join "" [ "Generated based on ", currentModulePath |> Path.toString Name.toTitleCase "." ])) + (Scala.Annotated [] + (Scala.Object + { modifiers = + [] + , name = + moduleName |> Name.toTitleCase + , members = + moduleTypeDefinitions ++ functionMembers + , extends = + [] + , body = Nothing + } + ) + ) + ] + } + in + [ ( moduleUnit, membersIssues ) ] + + +processFunctionMember : + Name.Name + -> AccessControlled (Documented (Value.Definition () (Type ()))) + -> Package.PackageName + -> Path + -> GlobalDefinitionInformation () + -> CustomizationOptions + -> ( List Scala.MemberDecl, List Scala.ImportDecl, GenerationIssues ) +processFunctionMember valueName accessControlledValueDef currentPackagePath currentModulePath ctxInfo customizationOptions = + let + fullFunctionName = + FQName.fQName currentPackagePath currentModulePath valueName + + ( mappedFunction, issues ) = + mapFunctionDefinition valueName accessControlledValueDef currentPackagePath currentModulePath ctxInfo + + issuesDict = + if List.isEmpty issues then + Dict.empty + + else + Dict.insert fullFunctionName issues Dict.empty + in + case tryToApplyPostConversionCustomization fullFunctionName mappedFunction customizationOptions of + Just ( mapped, imports ) -> + ( mapped, imports, issuesDict ) + + _ -> + ( [ mappedFunction ], [], issuesDict ) + + +mapFunctionDefinition : Name.Name -> AccessControlled (Documented (Value.Definition () (Type ()))) -> Path -> Path -> GlobalDefinitionInformation () -> ( Scala.MemberDecl, List GenerationIssue ) +mapFunctionDefinition functionName body currentPackagePath modulePath ( typeContextInfo, functionsInfo, inlineInfo ) = + let + fullFunctionName = + FQName.fQName currentPackagePath modulePath functionName + + functionClassification = + getFunctionClassification fullFunctionName functionsInfo + + parameters = + processParameters body.value.value.inputTypes functionClassification typeContextInfo + + parameterNames = + body.value.value.inputTypes |> List.map (\( name, _, _ ) -> name) + + valueMappingContext = + { emptyValueMappingContext + | typesContextInfo = typeContextInfo + , parameters = parameterNames + , functionClassificationInfo = functionsInfo + , currentFunctionClassification = functionClassification + , packagePath = currentPackagePath + , globalValuesToInline = inlineInfo + } + + localDeclarations = + body.value.value.inputTypes + |> List.filterMap (checkForDataFrameColumndsDeclaration typeContextInfo) + + ( bodyCandidate, issues ) = + mapFunctionBody body.value.value (includeDataFrameInfo localDeclarations valueMappingContext) + + returnTypeToGenerate = + mapFunctionReturnType body.value.value.outputType functionClassification typeContextInfo + + resultingFunction = + Scala.FunctionDecl + { modifiers = [] + , name = mapValueName functionName + , typeArgs = [] + , args = addImplicitSession parameters + , returnType = + Just returnTypeToGenerate + , body = + case ( localDeclarations |> List.map Tuple.first, bodyCandidate ) of + ( [], bodyToUse ) -> + Just bodyToUse + + ( declarations, bodyToUse ) -> + Just (Scala.Block declarations bodyToUse) + } + in + ( resultingFunction, issues ) + + +addImplicitSession : List (List Scala.ArgDecl) -> List (List Scala.ArgDecl) +addImplicitSession args = + case args of + [] -> + args + + _ -> + let + implicitArg = + { modifiers = [ Scala.Implicit ] + , tpe = typeRefForSnowparkType "Session" + , name = "sfSession" + , defaultValue = Nothing + } + in + args ++ [ [ implicitArg ] ] + + +includeDataFrameInfo : List ( Scala.MemberDecl, ( String, FQName.FQName ) ) -> ValueMappingContext -> ValueMappingContext +includeDataFrameInfo declInfos ctx = + let + newDataFrameInfo = + declInfos + |> List.map (\( _, ( varName, typeFullName ) ) -> ( typeFullName, varName )) + |> Dict.fromList + in + { ctx | dataFrameColumnsObjects = Dict.union ctx.dataFrameColumnsObjects newDataFrameInfo } + + +checkForDataFrameColumndsDeclaration : MappingContextInfo () -> ( Name.Name, va, Type () ) -> Maybe ( Scala.MemberDecl, ( String, FQName.FQName ) ) +checkForDataFrameColumndsDeclaration ctx ( name, _, tpe ) = + let + varNewName = + (name |> Name.toCamelCase) ++ "Columns" + in + case tpe of + Type.Reference _ _ [ (Type.Reference _ typeName _) as argType ] -> + if isCandidateForDataFrame tpe ctx then + Just ( generateLocalVariableForDataFrameColumns ctx ( varNewName, name, argType ), ( varNewName, typeName ) ) + + else + Nothing + + _ -> + Nothing + + +generateLocalVariableForDataFrameColumns : MappingContextInfo () -> ( String, Name.Name, Type a ) -> Scala.MemberDecl +generateLocalVariableForDataFrameColumns ctx ( name, originalName, tpe ) = + let + nameInfo = + isTypeReferenceToSimpleTypesRecord tpe ctx + + typeNameInfo = + Maybe.map + (\( typePath, simpleTypeName ) -> Just (Scala.TypeRef typePath (simpleTypeName |> Name.toTitleCase))) + nameInfo + + objectReference = + Maybe.map + (\( typePath, simpleTypeName ) -> + Scala.New typePath ((simpleTypeName |> Name.toTitleCase) ++ "Wrapper") [ Scala.ArgValue Nothing (Scala.Variable (Name.toCamelCase originalName)) ] + ) + nameInfo + in + Scala.ValueDecl + { modifiers = [] + , pattern = Scala.NamedMatch name + , valueType = Maybe.withDefault Nothing typeNameInfo + , value = Maybe.withDefault Scala.Unit objectReference + } + + +generateArgumentDeclarationForFunction : MappingContextInfo () -> FunctionClassification -> ( Name.Name, Type (), Type () ) -> List Scala.ArgDecl +generateArgumentDeclarationForFunction ctx currentFunctionClassification ( name, _, tpe ) = + [ Scala.ArgDecl [] (mapTypeReference tpe currentFunctionClassification ctx) (name |> generateParameterName) Nothing ] + + +generateParameterName : Name.Name -> String +generateParameterName name = + let + scalaName = + name |> Name.toCamelCase + in + if Set.member scalaName scalaKeywords || Set.member scalaName javaObjectMethods then + "_" ++ scalaName + + else + scalaName + + +processParameters : List ( Name.Name, Type (), Type () ) -> FunctionClassification -> MappingContextInfo () -> List (List Scala.ArgDecl) +processParameters inputTypes currentFunctionClassification ctx = + inputTypes |> List.map (generateArgumentDeclarationForFunction ctx currentFunctionClassification) + + +mapFunctionBody : Value.Definition () (Type ()) -> ValueMappingContext -> ( Scala.Value, List GenerationIssue ) +mapFunctionBody value ctx = + let + functionToMap = + if ctx.currentFunctionClassification == FromComplexValuesToDataFrames || ctx.currentFunctionClassification == FromComplexToValues then + FunctionMappingsForPlainScala.mapValueForPlainScala + + else + mapValue + in + functionToMap value.body ctx diff --git a/src/Morphir/Snowpark/Constants.elm b/src/Morphir/Snowpark/Constants.elm new file mode 100644 index 000000000..b9573bb00 --- /dev/null +++ b/src/Morphir/Snowpark/Constants.elm @@ -0,0 +1,103 @@ +module Morphir.Snowpark.Constants exposing + ( AliasVariableInfo + , LambdaInfo + , MapValueType + , MappingFunc + , ValueGenerationResult + , VariableInformation + , applyForSnowparkTypesType + , applyForSnowparkTypesTypeExpr + , applySnowparkFunc + , transformToArgsValue + , typeRefForSnowparkType + , typeRefForSnowparkTypesType + ) + +import Morphir.IR.Name as Name +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value exposing (Pattern(..), TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.MappingContext exposing (ValueMappingContext) + + +snowflakeNamespace : List String +snowflakeNamespace = + [ "com", "snowflake", "snowpark" ] + + +functionsNamespace : List String +functionsNamespace = + snowflakeNamespace ++ [ "functions" ] + + +typesNamespace : List String +typesNamespace = + snowflakeNamespace ++ [ "types" ] + + +applySnowparkFunc : String -> List Scala.Value -> Scala.Value +applySnowparkFunc name args = + applyFunctionName functionsNamespace name args + + +transformToArgsValue : List Scala.Value -> List Scala.ArgValue +transformToArgsValue valueList = + List.map (\x -> Scala.ArgValue Nothing x) valueList + + +typeRefForSnowparkType : String -> Scala.Type +typeRefForSnowparkType typeName = + Scala.TypeRef snowflakeNamespace typeName + + +typeRefForSnowparkTypesType : String -> Scala.Type +typeRefForSnowparkTypesType typeName = + Scala.TypeRef typesNamespace typeName + + +applyForSnowparkTypesType : String -> List Scala.Value -> Scala.Value +applyForSnowparkTypesType name args = + applyFunctionName typesNamespace name args + + +applyForSnowparkTypesTypeExpr : String -> Scala.Value +applyForSnowparkTypesTypeExpr name = + Scala.Ref typesNamespace name + + +applyFunctionName : List String -> String -> List Scala.Value -> Scala.Value +applyFunctionName namespace name args = + Scala.Apply + (Scala.Ref namespace name) + (args |> List.map (\v -> Scala.ArgValue Nothing v)) + + +type alias ValueGenerationResult = + ( Scala.Value, List GenerationIssue ) + + +type alias MapValueType = + TypedValue -> ValueMappingContext -> ( Scala.Value, List GenerationIssue ) + + +type alias VariableInformation = + ( List Scala.Value, List ( String, Scala.Value ) ) + + +type alias MappingFunc = + ( MapValueType, ValueMappingContext ) + + +type alias AliasVariableInfo = + { aliasName : List Scala.Value + , variables : VariableInformation + } + + +type alias LambdaInfo ta = + { lambdaPattern : Pattern (TypeIR.Type ()) + , lambdaBody : Value ta (TypeIR.Type ()) + , groupByName : Name.Name + , firstParameter : Name.Name + } diff --git a/src/Morphir/Snowpark/Customization.elm b/src/Morphir/Snowpark/Customization.elm new file mode 100644 index 000000000..07118b6c9 --- /dev/null +++ b/src/Morphir/Snowpark/Customization.elm @@ -0,0 +1,129 @@ +module Morphir.Snowpark.Customization exposing + ( CustomizationOptions + , emptyCustomizationOptions + , generateCacheCode + , loadCustomizationOptions + , tryToApplyPostConversionCustomization + ) + +import Json.Decode as Decode +import Morphir.IR.FQName exposing (FQName) +import Morphir.IR.NodeId exposing (NodeID(..)) +import Morphir.SDK.Dict as SDKDict +import Morphir.Scala.AST as Scala exposing (ImportName(..)) +import Set exposing (Set) + + +type alias CustomizationOptions = + { functionsToInline : Set FQName + , functionsToCache : Set FQName + } + + +emptyCustomizationOptions : CustomizationOptions +emptyCustomizationOptions = + CustomizationOptions Set.empty Set.empty + + +loadCustomizationOptions : SDKDict.Dict NodeID Decode.Value -> CustomizationOptions +loadCustomizationOptions optionsDict = + let + decodeFirstElementAsString = + Decode.decodeValue (Decode.index 0 Decode.string) + + optsList = + optionsDict + |> SDKDict.toList + + functions = + optsList + |> List.filterMap + (\( id, value ) -> + case id of + ValueID fullName _ -> + Just ( fullName, value ) + + _ -> + Nothing + ) + + ( functionsToCache, valuesToInline ) = + functions + |> List.foldr + (\( fullName, valueDec ) (( toCache, toInline ) as current) -> + case decodeFirstElementAsString valueDec of + Ok "cacheResult" -> + ( Set.insert fullName toCache, toInline ) + + Ok "inlineElement" -> + ( toCache, Set.insert fullName toInline ) + + _ -> + current + ) + ( Set.empty, Set.empty ) + in + { functionsToInline = valuesToInline + , functionsToCache = functionsToCache + } + + +generateCacheCode : String -> Scala.MemberDecl -> Maybe Scala.Type -> Scala.MemberDecl +generateCacheCode cacheName decl returnType = + case decl of + Scala.FunctionDecl funcInfo -> + let + funcArgs = + funcInfo.args |> List.concatMap (\t -> t |> List.map (\t2 -> Scala.Variable t2.name)) + + body = + Maybe.withDefault (Scala.Variable "_") funcInfo.body + + expressionToCache = + case returnType of + Just (Scala.TypeRef _ "DataFrame") -> + Scala.Select body "cacheResult" + + _ -> + body + + getOrElseUpdateCall = + Scala.Apply (Scala.Ref [ cacheName ] "getOrElseUpdate") + [ Scala.ArgValue Nothing (Scala.Tuple funcArgs) + , Scala.ArgValue Nothing expressionToCache + ] + in + Scala.FunctionDecl { funcInfo | body = Just getOrElseUpdateCall } + + _ -> + decl + + +tryToApplyPostConversionCustomization : FQName -> Scala.MemberDecl -> CustomizationOptions -> Maybe ( List Scala.MemberDecl, List Scala.ImportDecl ) +tryToApplyPostConversionCustomization fullFunctionName mappedFunction customizationOptions = + case ( Set.member fullFunctionName customizationOptions.functionsToCache, mappedFunction ) of + ( True, Scala.FunctionDecl funcInfo ) -> + Just + ( [ generateCacheCode (funcInfo.name ++ "Cache") mappedFunction funcInfo.returnType + , Scala.ValueDecl + { modifiers = [] + , pattern = Scala.NamedMatch (funcInfo.name ++ "Cache") + , valueType = + Just + (Scala.TypeApply + (Scala.TypeRef [ "scala", "collection", "concurrent" ] "Map") + [ Scala.TupleType (funcInfo.args |> List.concatMap (\t -> t |> List.map (\t2 -> t2.tpe))), Maybe.withDefault (Scala.TypeVar "_") funcInfo.returnType ] + ) + , value = + Scala.Select (Scala.New [ "java", "util", "concurrent" ] "ConcurrentHashMap" []) "asScala" + } + ] + , [ Scala.ImportDecl False [ "scala", "collection", "JavaConverters", "_" ] [] ] + ) + + _ -> + if Set.member fullFunctionName customizationOptions.functionsToInline then + Just ( [], [] ) + + else + Nothing diff --git a/src/Morphir/Snowpark/FunctionMappingsForPlainScala.elm b/src/Morphir/Snowpark/FunctionMappingsForPlainScala.elm new file mode 100644 index 000000000..331017f93 --- /dev/null +++ b/src/Morphir/Snowpark/FunctionMappingsForPlainScala.elm @@ -0,0 +1,305 @@ +module Morphir.Snowpark.FunctionMappingsForPlainScala exposing (mapFunctionCall, mapValueForPlainScala) + +import Dict +import Morphir.IR.FQName as FQName +import Morphir.IR.Name as Name +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value as ValueIR exposing (Pattern(..), TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.AccessElementMapping exposing (mapReferenceAccess) +import Morphir.Snowpark.Constants as Constants exposing (ValueGenerationResult) +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.LetMapping exposing (mapLetDefinition) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations as MapDfOperations +import Morphir.Snowpark.MapFunctionsMapping + exposing + ( FunctionMappingTable + , basicsFunctionName + , dataFrameMappings + , listFunctionName + , mapUncurriedFunctionCall + ) +import Morphir.Snowpark.MappingContext exposing (ValueMappingContext, isCandidateForDataFrame, isUnionTypeWithoutParams) +import Morphir.Snowpark.Operatorsmaps exposing (mapOperator) +import Morphir.Snowpark.PatternMatchMapping exposing (PatternMatchValues) +import Morphir.Snowpark.ReferenceUtils exposing (curryCall, errorValueAndIssue, mapLiteralToPlainLiteral) + + +mapValueForPlainScala : TypedValue -> ValueMappingContext -> ValueGenerationResult +mapValueForPlainScala value ctx = + case value of + Apply _ _ _ -> + mapFunctionCall value mapValueForPlainScala ctx + + Literal tpe literal -> + ( mapLiteralToPlainLiteral tpe literal, [] ) + + LetDefinition _ name definition body -> + mapLetDefinition name definition body mapValueForPlainScala ctx + + Reference tpe name -> + mapReferenceAccess tpe name mapValueForPlainScala ctx + + PatternMatch tpe expr cases -> + mapPatternMatch ( tpe, expr, cases ) mapValueForPlainScala ctx + + _ -> + MapDfOperations.mapValue value ctx + + +mapPatternMatch : PatternMatchValues -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapPatternMatch ( tpe, expr, cases ) mapValue ctx = + let + ( convertedCases, casesIssues ) = + cases + |> List.map (mapCaseOfCase mapValue ctx) + |> List.unzip + + ( mappedExpr, exprIssues ) = + mapValue expr ctx + in + ( Scala.Match mappedExpr (Scala.MatchCases convertedCases), exprIssues ++ List.concat casesIssues ) + + +mapCaseOfCase : Constants.MapValueType -> ValueMappingContext -> ( Pattern (TypeIR.Type ()), TypedValue ) -> ( ( Scala.Pattern, Scala.Value ), List GenerationIssue ) +mapCaseOfCase mapValue ctx ( sourcePattern, sourceExpr ) = + let + ( convertedExpr, convertedExprIssues ) = + mapValue sourceExpr ctx + in + case sourcePattern of + ConstructorPattern _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "just" ] ) [ AsPattern _ (WildcardPattern _) varName ] -> + ( ( Scala.UnapplyMatch [] "Some" [ Scala.NamedMatch (Name.toCamelCase varName) ], convertedExpr ), convertedExprIssues ) + + ConstructorPattern _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "nothing" ] ) [] -> + ( ( Scala.UnapplyMatch [] "None" [], convertedExpr ), convertedExprIssues ) + + ConstructorPattern (TypeIR.Reference _ fullTypeName _) fullName [] -> + if isUnionTypeWithoutParams fullTypeName ctx.typesContextInfo then + ( ( Scala.LiteralMatch (Scala.StringLit (Name.toTitleCase (FQName.getLocalName fullName))), convertedExpr ), convertedExprIssues ) + + else + ( ( Scala.NamedMatch "CONSTRUCTOR_PATTERN_NOT_CONVERTED", convertedExpr ) + , "Constructor pattern not support for Scala function" :: convertedExprIssues + ) + + _ -> + ( ( Scala.NamedMatch "PATTERN_NOT_CONVERTED", convertedExpr ) + , "Pattern not generated for Scala function" :: convertedExprIssues + ) + + +mapFunctionCall : ValueIR.Value () (TypeIR.Type ()) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapFunctionCall value mapValue ctx = + case value of + ValueIR.Apply _ func arg -> + mapUncurriedFunctionCall (ValueIR.uncurryApply func arg) mapValue actualMappingTable ctx + + _ -> + errorValueAndIssue "invalid function call" + + +mergeMappingDictionaries : FunctionMappingTable -> FunctionMappingTable -> FunctionMappingTable +mergeMappingDictionaries first second = + Dict.union first second + + +specificMappings : FunctionMappingTable +specificMappings = + [ ( listFunctionName [ "range" ], mapListRangeFunction ) + , ( listFunctionName [ "map" ], mapListMapFunction ) + , ( listFunctionName [ "sum" ], mapListSumFunction ) + , ( listFunctionName [ "maximum" ], mapListMaximumFunction ) + , ( basicsFunctionName [ "negate" ], mapNegateFunction ) + , ( basicsFunctionName [ "max" ], mapMaxMinFunction "max" ) + , ( basicsFunctionName [ "min" ], mapMaxMinFunction "min" ) + , ( basicsFunctionName [ "to", "float" ], mapToFloatFunctionCall ) + ] + |> Dict.fromList + + +actualMappingTable : FunctionMappingTable +actualMappingTable = + mergeMappingDictionaries specificMappings dataFrameMappings + + +mapListRangeFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListRangeFunction ( _, args ) mapValue ctx = + case args of + [ start, end ] -> + let + ( mappedStart, startIssues ) = + mapValue start ctx + + ( mappedEnd, endIssues ) = + mapValue end ctx + + endExpr = + Scala.BinOp mappedEnd "+" (Scala.Literal (Scala.IntegerLit 1)) + in + ( Scala.Apply (Scala.Select (Scala.Variable "Seq") "range") [ Scala.ArgValue Nothing mappedStart, Scala.ArgValue Nothing endExpr ] + , startIssues ++ endIssues + ) + + _ -> + errorValueAndIssue "List range scenario not supported" + + +mapListMapFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListMapFunction (( _, args ) as call) mapValue ctx = + case args of + [ action, collection ] -> + if isCandidateForDataFrame (ValueIR.valueAttribute collection) ctx.typesContextInfo then + MapDfOperations.mapValue (curryCall call) ctx + + else + let + ( mappedStart, startIssues ) = + mapMapPredicate action mapValue ctx + + ( mappedEnd, endIssues ) = + mapValue collection ctx + in + ( Scala.Apply (Scala.Select mappedEnd "map") [ Scala.ArgValue Nothing mappedStart ], startIssues ++ endIssues ) + + _ -> + errorValueAndIssue "List map scenario not supported" + + +mapListSumFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListSumFunction (( _, args ) as call) mapValue ctx = + let + collectionComesFromDataFrameProjection : TypedValue -> Bool + collectionComesFromDataFrameProjection collection = + case collection of + ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "map" ] )) _) innerCollection -> + isCandidateForDataFrame (ValueIR.valueAttribute innerCollection) ctx.typesContextInfo + + _ -> + False + in + case args of + [ collection ] -> + if collectionComesFromDataFrameProjection collection then + MapDfOperations.mapValue (curryCall call) ctx + + else + let + ( mappedCollection, collectionIssues ) = + mapValue collection ctx + in + ( Scala.Apply (Scala.Select mappedCollection "reduce") [ Scala.ArgValue Nothing (Scala.BinOp Scala.Wildcard "+" Scala.Wildcard) ] + , collectionIssues + ) + + _ -> + errorValueAndIssue "List sum scenario not supported" + + +mapListMaximumFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListMaximumFunction ( _, args ) mapValue ctx = + case args of + [ collection ] -> + let + ( mappedCollection, collectionIssues ) = + mapValue collection ctx + in + ( Scala.Apply (Scala.Select mappedCollection "reduceOption") + [ Scala.ArgValue Nothing (Scala.BinOp Scala.Wildcard "max" Scala.Wildcard) ] + , collectionIssues + ) + + _ -> + errorValueAndIssue "List maximum scenario not supported" + + +mapNegateFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapNegateFunction ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Scala.UnOp "-" mappedValue, valueIssues ) + + _ -> + errorValueAndIssue "negate scenario not supported" + + +adjustIntegerFloatLiteral : Scala.Value -> Scala.Value +adjustIntegerFloatLiteral value = + case value of + Scala.Literal (Scala.FloatLit innerValue) -> + if innerValue == (floor >> toFloat) innerValue then + Scala.Select value "toDouble" + + else + value + + _ -> + value + + +mapMaxMinFunction : String -> ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapMaxMinFunction name ( _, args ) mapValue ctx = + case args of + [ value1, value2 ] -> + let + ( mappedValue1, value1Issues ) = + mapValue value1 ctx + + ( mappedValue2, value2Issues ) = + mapValue value2 ctx + in + ( Scala.BinOp (adjustIntegerFloatLiteral mappedValue1) name (adjustIntegerFloatLiteral mappedValue2) + , value1Issues ++ value2Issues + ) + + _ -> + errorValueAndIssue (name ++ "scenario not supported") + + +mapMapPredicate : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapMapPredicate action mapValue ctx = + case action of + ValueIR.Lambda _ (ValueIR.AsPattern _ (ValueIR.WildcardPattern _) lmdarg) body -> + let + ( generatedBody, bodyIssues ) = + mapValue body ctx + in + ( Scala.Lambda [ ( Name.toCamelCase lmdarg, Nothing ) ] generatedBody, bodyIssues ) + + _ -> + mapValue action ctx + + +mapForOperatorCall : Name.Name -> TypedValue -> TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapForOperatorCall optname left right mapValue ctx = + let + ( leftValue, leftValueIssues ) = + mapValue left ctx + + ( rightValue, rightValueIssues ) = + mapValue right ctx + + operatorname = + mapOperator optname + in + ( Scala.BinOp leftValue operatorname rightValue + , leftValueIssues ++ rightValueIssues + ) + + +mapToFloatFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapToFloatFunctionCall ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Scala.Select mappedValue "toDouble", valueIssues ) + + _ -> + errorValueAndIssue "`toFloat` scenario not supported" diff --git a/src/Morphir/Snowpark/GenerationReport.elm b/src/Morphir/Snowpark/GenerationReport.elm new file mode 100644 index 000000000..c574d3d2e --- /dev/null +++ b/src/Morphir/Snowpark/GenerationReport.elm @@ -0,0 +1,167 @@ +module Morphir.Snowpark.GenerationReport exposing + ( GenerationIssue + , GenerationIssues + , addGenerationIssue + , createGenerationReport + ) + +import Dict exposing (Dict) +import Morphir.File.SourceCode exposing (Doc) +import Morphir.IR.FQName as FQName exposing (FQName) +import Morphir.Snowpark.Customization exposing (CustomizationOptions) +import Morphir.Snowpark.MappingContext + exposing + ( FunctionClassification(..) + , GlobalDefinitionInformation + , isRecordWithSimpleTypes + ) + + +type alias GenerationIssue = + String + + +type alias GenerationIssues = + Dict FQName (List GenerationIssue) + + +addGenerationIssue : FQName -> GenerationIssue -> GenerationIssues -> GenerationIssues +addGenerationIssue fullElementName issueInfo generationIssues = + Dict.update fullElementName + (\oldValueMaybe -> Just <| issueInfo :: Maybe.withDefault [] oldValueMaybe) + generationIssues + + +type MdElem + = Header1 String + | Header2 String + | Header3 String + | Paragraph (List MdInline) + | BulletList (List (List MdInline)) + + +type MdInline + = Span String + | Strong String + | Code String + + +type alias MdDoc = + List MdElem + + +toStringMd : MdDoc -> List String +toStringMd doc = + doc + |> List.map toStringMdElem + |> List.intersperse [ "\n" ] + |> List.concat + + +toStringMdElem : MdElem -> List String +toStringMdElem e = + case e of + Header1 txt -> + [ "# ", txt, "\n" ] + + Header2 txt -> + [ "\n", "## ", txt, "\n" ] + + Header3 txt -> + [ "\n", "### ", txt, "\n" ] + + Paragraph items -> + items |> List.map toStringMdInline + + BulletList items -> + items + |> List.map (\innerList -> "- " :: List.map toStringMdInline innerList) + |> List.intersperse [ "\n" ] + |> List.concat + + +toStringMdInline : MdInline -> String +toStringMdInline inlineElement = + case inlineElement of + Span str -> + str + + Strong str -> + "**" ++ str ++ "**" + + Code str -> + "`" ++ str ++ "`" + + +generateSortedListOfCodeFromNames : List FQName -> List (List MdInline) +generateSortedListOfCodeFromNames names = + names + |> List.map FQName.toString + |> List.sort + |> List.map (\fname -> [ Code fname ]) + + +generateDataFrameListing : GlobalDefinitionInformation () -> List MdElem +generateDataFrameListing ( typeInformation, _, _ ) = + let + bullets = + typeInformation + |> Dict.toList + |> List.filter (\( fname, _ ) -> isRecordWithSimpleTypes fname typeInformation) + |> List.map Tuple.first + |> generateSortedListOfCodeFromNames + in + [ Header2 "Types identified as DataFrames" + , BulletList bullets + ] + + +generateIssuesReport : GenerationIssues -> List MdElem +generateIssuesReport issues = + if Dict.isEmpty issues then + [] + + else + Header2 "Generation issues" + :: (issues + |> Dict.toList + |> List.concatMap + (\( func, innerIssues ) -> [ Header3 (FQName.toString func), BulletList (innerIssues |> List.map (\i -> [ Span i ])) ]) + ) + + +generateFunctionClassificationListing : GlobalDefinitionInformation () -> List MdElem +generateFunctionClassificationListing ( _, functionClassification, _ ) = + functionClassification + |> Dict.toList + |> List.partition + (\( _, cls ) -> + case cls of + FromComplexValuesToDataFrames -> + True + + FromComplexToValues -> + True + + _ -> + False + ) + |> (\( complex, df ) -> + [ Header2 "Functions generated using DataFrame operations strategy" + , BulletList (df |> List.map Tuple.first |> generateSortedListOfCodeFromNames) + , Header2 "Functions generated using Scala strategy" + , BulletList (complex |> List.map Tuple.first |> generateSortedListOfCodeFromNames) + ] + ) + + +createGenerationReport : GlobalDefinitionInformation () -> CustomizationOptions -> GenerationIssues -> Doc +createGenerationReport ctx _ issues = + let + mddoc = + Header1 "Generation report" + :: generateIssuesReport issues + ++ generateFunctionClassificationListing ctx + ++ generateDataFrameListing ctx + in + String.join "" (toStringMd mddoc) diff --git a/src/Morphir/Snowpark/JoinMapping.elm b/src/Morphir/Snowpark/JoinMapping.elm new file mode 100644 index 000000000..d8152d227 --- /dev/null +++ b/src/Morphir/Snowpark/JoinMapping.elm @@ -0,0 +1,164 @@ +module Morphir.Snowpark.JoinMapping exposing (processJoinBody, processJoinProjection) + +import Dict +import Morphir.IR.Name as Name +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value as ValueIR exposing (TypedValue) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants as Constants exposing (ValueGenerationResult) +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.MappingContext exposing (ValueMappingContext) +import Morphir.Snowpark.ReferenceUtils exposing (errorValueAndIssue) + + +processJoinProjection : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ( List Scala.Value, List GenerationIssue ) +processJoinProjection projection mapValue ctx = + case projection of + ValueIR.Lambda _ _ (ValueIR.Record _ record) -> + let + listFields = + Dict.toList record + + ( variablesExpr, varIssues ) = + listFields + |> List.map transformMaybeValueToField + |> List.map (\( _, x ) -> mapValue x ctx) + |> List.unzip + + variables = + variablesExpr + |> List.map (\x -> Scala.Select x "alias") + + alias = + listFields |> List.map (\( x, _ ) -> Scala.Literal (Scala.StringLit (Name.toCamelCase x))) + + selectColumns = + List.map2 (\name variable -> Scala.Apply variable [ Scala.ArgValue Nothing name ]) alias variables + in + ( selectColumns, List.concat varIssues ) + + _ -> + ( [ Scala.Literal <| Scala.StringLit "Projection" ], [] ) + + +transformMaybeValueToField : ( Name.Name, ValueIR.Value () (TypeIR.Type ()) ) -> ( Name.Name, ValueIR.Value () (TypeIR.Type ()) ) +transformMaybeValueToField ( name, value ) = + case value of + ValueIR.Apply (TypeIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ returnType ]) (ValueIR.Apply _ _ (ValueIR.Lambda _ _ (ValueIR.Field _ _ accessField))) (ValueIR.Variable (TypeIR.Reference _ _ [ variableRef ]) variableField) -> + let + variable = + ValueIR.Variable variableRef variableField + + field = + ValueIR.Field returnType variable accessField + in + ( name, field ) + + _ -> + ( name, value ) + + +processJoinsLambda : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +processJoinsLambda lambdaValue mapValue ctx = + case lambdaValue of + ValueIR.Lambda _ (ValueIR.AsPattern _ _ _) (ValueIR.Lambda _ (ValueIR.AsPattern _ _ _) lambdaBody) -> + processJoinFunctionBody lambdaBody mapValue ctx + + ValueIR.Lambda _ _ (ValueIR.Lambda _ _ lambdaBody) -> + processJoinFunctionBody lambdaBody mapValue ctx + + _ -> + errorValueAndIssue "`Join` scenario not supported" + + +processInternalJoin : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ( List Scala.ArgValue, List GenerationIssue ) +processInternalJoin value mapValue ctx = + case value of + ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], joinName )) (ValueIR.Variable _ arg2)) ((ValueIR.Lambda _ _ _) as lambdaSection) -> + let + ( lambdaBodyScala, bodyIssues ) = + processJoinsLambda lambdaSection mapValue ctx + + joinTypeName = + getJoinType joinName + in + ( [ Scala.ArgValue Nothing (Scala.Variable (Name.toCamelCase arg2)) + , Scala.ArgValue Nothing lambdaBodyScala + , Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit joinTypeName)) + ] + , bodyIssues + ) + + _ -> + ( [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "Unsupported Join")) ], [] ) + + +processJoinBody : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +processJoinBody joinValue mapValue ctx = + case joinValue of + ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], joinName )) (ValueIR.Variable _ arg2)) ((ValueIR.Lambda _ _ _) as lambdaSection)) (ValueIR.Variable _ arg1) -> + let + ( lambdaBodyScala, bodyIssues ) = + processJoinsLambda lambdaSection mapValue ctx + + joinTypeName = + getJoinType joinName + in + ( Scala.Apply + (Scala.Select (Scala.Variable (Name.toCamelCase arg1)) "join") + [ Scala.ArgValue Nothing (Scala.Variable (Name.toCamelCase arg2)) + , Scala.ArgValue Nothing lambdaBodyScala + , Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit joinTypeName)) + ] + , bodyIssues + ) + + ValueIR.Apply _ ((ValueIR.Apply _ _ _) as internalJoin) ((ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], joinName )) (ValueIR.Variable _ arg2)) _) _) as firstJoin) -> + if List.member "join" joinName then + let + ( firstJoinResult, firstErrors ) = + processJoinBody firstJoin mapValue ctx + + ( secondJoinResult, secondErrors ) = + processInternalJoin internalJoin mapValue ctx + + preresult = + Scala.Select firstJoinResult "join" + + result = + Scala.Apply preresult secondJoinResult + in + ( result + , List.append firstErrors secondErrors + ) + + else + errorValueAndIssue "'Join' scenario not supported" + + _ -> + errorValueAndIssue "'Join' scenario not supported" + + +processJoinFunctionBody : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +processJoinFunctionBody value mapValue ctx = + case value of + ValueIR.Apply _ x y -> + mapValue value ctx + + _ -> + errorValueAndIssue "Join Body EXCEPTION" + + +getJoinType : Name.Name -> String +getJoinType name = + if List.member "inner" name then + "inner" + + else if List.member "right" name then + "right" + + else if List.member "left" name then + "left" + + else + "Unsupported join Type" diff --git a/src/Morphir/Snowpark/LetMapping.elm b/src/Morphir/Snowpark/LetMapping.elm new file mode 100644 index 000000000..9cd21550f --- /dev/null +++ b/src/Morphir/Snowpark/LetMapping.elm @@ -0,0 +1,90 @@ +module Morphir.Snowpark.LetMapping exposing (collectNestedLetDeclarations, mapLetDefinition) + +import List +import Morphir.IR.Literal exposing (Literal(..)) +import Morphir.IR.Name as Name +import Morphir.IR.Type exposing (Type) +import Morphir.IR.Value as Value exposing (Pattern(..), TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants exposing (MapValueType, ValueGenerationResult) +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.MappingContext + exposing + ( FunctionClassification(..) + , ValueMappingContext + , addLocalDefinitions + ) +import Morphir.Snowpark.TypeRefMapping exposing (mapTypeReference) + + +mapLetDefinition : Name.Name -> Value.Definition () (Type ()) -> TypedValue -> MapValueType -> ValueMappingContext -> ValueGenerationResult +mapLetDefinition name definition body mapValue ctx = + let + ( pairs, bodyToConvert ) = + collectNestedLetDeclarations body [] + + declsToProcess = + ( name, definition ) :: pairs + + contextForLetBody = + addLocalDefinitions (declsToProcess |> List.map Tuple.first) ctx + + ( decls, issues ) = + declsToProcess + |> List.map (\p -> mapLetDeclaration p mapValue contextForLetBody) + |> List.unzip + + ( mappedBody, mappedBodyIssues ) = + mapValue bodyToConvert contextForLetBody + in + ( Scala.Block decls mappedBody, mappedBodyIssues ++ List.concat issues ) + + +mapLetDeclaration : ( Name.Name, Value.Definition () (Type ()) ) -> MapValueType -> ValueMappingContext -> ( Scala.MemberDecl, List GenerationIssue ) +mapLetDeclaration ( name, decl ) mapValue ctx = + case decl.body of + Value.Lambda _ (Value.AsPattern t _ paramName) body -> + let + ( mappedBody, mappedBodyIssues ) = + mapValue body ctx + + mappedArgType = + mapTypeReference t ctx.currentFunctionClassification ctx.typesContextInfo + in + ( Scala.FunctionDecl + { modifiers = [] + , name = Name.toCamelCase name + , typeArgs = [] + , args = [ [ Scala.ArgDecl [] mappedArgType (Name.toCamelCase paramName) Nothing ] ] + , returnType = Nothing + , body = Just mappedBody + } + , mappedBodyIssues + ) + + _ -> + let + ( mappedBody, mappedBodyIssues ) = + mapValue decl.body ctx + in + ( Scala.ValueDecl + { modifiers = [] + , pattern = Scala.NamedMatch (name |> Name.toCamelCase) + , valueType = Nothing + , value = mappedBody + } + , mappedBodyIssues + ) + + +collectNestedLetDeclarations : + TypedValue + -> List ( Name.Name, Value.Definition () (Type ()) ) + -> ( List ( Name.Name, Value.Definition () (Type ()) ), TypedValue ) +collectNestedLetDeclarations currentBody collectedPairs = + case currentBody of + Value.LetDefinition _ name definition body -> + collectNestedLetDeclarations body (( name, definition ) :: collectedPairs) + + _ -> + ( List.reverse collectedPairs, currentBody ) diff --git a/src/Morphir/Snowpark/MapExpressionsToDataFrameOperations.elm b/src/Morphir/Snowpark/MapExpressionsToDataFrameOperations.elm new file mode 100644 index 000000000..92cb4df78 --- /dev/null +++ b/src/Morphir/Snowpark/MapExpressionsToDataFrameOperations.elm @@ -0,0 +1,304 @@ +module Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) + +import Dict +import List +import Morphir.IR.AccessControlled exposing (Access(..)) +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal exposing (Literal(..)) +import Morphir.IR.Name as Name +import Morphir.IR.Type as Type exposing (Type) +import Morphir.IR.Value as Value exposing (Pattern(..), TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.AccessElementMapping + exposing + ( mapConstructorAccess + , mapFieldAccess + , mapReferenceAccess + , mapVariableAccess + ) +import Morphir.Snowpark.Constants as Constants exposing (ValueGenerationResult, applySnowparkFunc) +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.LetMapping exposing (mapLetDefinition) +import Morphir.Snowpark.MapFunctionsMapping as MapFunctionsMapping +import Morphir.Snowpark.MappingContext as MappingContext + exposing + ( FunctionClassification(..) + , ValueMappingContext + , getFieldInfoIfRecordType + , isAnonymousRecordWithSimpleTypes + , isFunctionClassificationReturningDataFrameExpressions + , isTypeRefToRecordWithComplexTypes + , isTypeRefToRecordWithSimpleTypes + , typeRefIsListOf + ) +import Morphir.Snowpark.PatternMatchMapping exposing (mapPatternMatch) +import Morphir.Snowpark.ReferenceUtils + exposing + ( errorValueAndIssue + , getListTypeParameter + , isTypeReferenceToSimpleTypesRecord + , mapLiteral + , scalaPathToModule + ) +import Morphir.Snowpark.Utils exposing (collectMaybeList) + + +mapValue : TypedValue -> ValueMappingContext -> ( Scala.Value, List GenerationIssue ) +mapValue value ctx = + case value of + Literal tpe literal -> + ( mapLiteral tpe literal, [] ) + + Field tpe val name -> + mapFieldAccess tpe val name ctx mapValue + + (Variable _ name) as varAccess -> + mapVariableAccess name varAccess ctx + + Constructor tpe name -> + mapConstructorAccess tpe name ctx + + List listType values -> + mapListCreation listType values ctx + + Reference tpe name -> + mapReferenceAccess tpe name mapValue ctx + + Apply _ _ _ -> + MapFunctionsMapping.mapFunctionsMapping value mapValue ctx + + PatternMatch tpe expr cases -> + mapPatternMatch ( tpe, expr, cases ) mapValue ctx + + IfThenElse _ condition thenExpr elseExpr -> + mapIfThenElse condition thenExpr elseExpr ctx + + LetDefinition _ name definition body -> + mapLetDefinition name definition body mapValue ctx + + FieldFunction _ name -> + ( Constants.applySnowparkFunc "col" [ Scala.Literal (Scala.StringLit (Name.toCamelCase name)) ], [] ) + + Value.Tuple _ tupleElements -> + mapTuple tupleElements ctx + + Value.Record tpe fields -> + mapRecordCreation tpe fields ctx + + Value.UpdateRecord tpe rec fieldUpdates -> + mapUpdateRecord tpe rec fieldUpdates ctx + + _ -> + errorValueAndIssue "Unsupported value element not generated" + + +mapUpdateRecord : Type () -> TypedValue -> Dict.Dict Name.Name TypedValue -> ValueMappingContext -> ( Scala.Value, List GenerationIssue ) +mapUpdateRecord recordType recordExpr fieldUpdates ctx = + if + isTypeRefToRecordWithSimpleTypes recordType ctx.typesContextInfo + || isAnonymousRecordWithSimpleTypes recordType ctx.typesContextInfo + then + getFieldInfoIfRecordType recordType ctx.typesContextInfo + |> Maybe.map + (\fields -> + let + ( mappedFields, fieldsIssues ) = + fields + |> List.map + (\( field, fieldType ) -> + Dict.get field fieldUpdates + |> Maybe.map (\updateExpr -> mapValue updateExpr ctx) + |> Maybe.withDefault (mapValue (Value.Field fieldType recordExpr field) ctx) + ) + |> List.unzip + in + ( applySnowparkFunc + "array_construct" + mappedFields + , List.concat fieldsIssues + ) + ) + |> Maybe.withDefault (errorValueAndIssue "Unsupported `update record` scenario") + + else + errorValueAndIssue "Unsupported `update record` scenario" + + +mapTuple : List TypedValue -> ValueMappingContext -> ValueGenerationResult +mapTuple tupleElements ctx = + let + ( args, issues ) = + tupleElements + |> List.map (\e -> mapValue e ctx) + |> List.unzip + in + ( Constants.applySnowparkFunc "array_construct" args, List.concat issues ) + + +mapRecordCreation : Type () -> Dict.Dict Name.Name TypedValue -> ValueMappingContext -> ValueGenerationResult +mapRecordCreation tpe fields ctx = + if isTypeRefToRecordWithComplexTypes tpe ctx.typesContextInfo then + mapRecordCreationToCaseClassCreation tpe fields ctx + + else if + (isTypeRefToRecordWithSimpleTypes tpe ctx.typesContextInfo + || isAnonymousRecordWithSimpleTypes tpe ctx.typesContextInfo + ) + && isFunctionClassificationReturningDataFrameExpressions ctx.currentFunctionClassification + then + MappingContext.getFieldInfoIfRecordType tpe ctx.typesContextInfo + |> Maybe.map + (\fieldInfo -> + collectMaybeList + (\( fieldName, _ ) -> + Dict.get fieldName fields + |> Maybe.map (\argExpr -> mapValue argExpr ctx) + ) + fieldInfo + ) + |> Maybe.withDefault Nothing + |> Maybe.map List.unzip + |> Maybe.map (\( args, issues ) -> ( applySnowparkFunc "array_construct" args, List.concat issues )) + |> Maybe.withDefault (errorValueAndIssue "Record creation not generated: could not get information about record.") + + else + errorValueAndIssue "Record creation not converted" + + +mapRecordCreationToCaseClassCreation : Type () -> Dict.Dict Name.Name TypedValue -> ValueMappingContext -> ValueGenerationResult +mapRecordCreationToCaseClassCreation tpe fields ctx = + case tpe of + Type.Reference _ fullName [] -> + let + caseClassReference = + Scala.Ref (scalaPathToModule fullName) (fullName |> FQName.getLocalName |> Name.toTitleCase) + + processArg : Name.Name -> TypedValue -> ( Scala.ArgValue, List GenerationIssue ) + processArg fieldName argValue = + let + ( mappedExpr, issues ) = + mapValue argValue ctx + in + ( Scala.ArgValue (Just (Name.toCamelCase fieldName)) mappedExpr, issues ) + + processArgs : List ( Name.Name, Type () ) -> Maybe (List ( Scala.ArgValue, List GenerationIssue )) + processArgs fieldsInfo = + fieldsInfo + |> collectMaybeList + (\( fieldName, _ ) -> + Dict.get fieldName fields + |> Maybe.map (processArg fieldName) + ) + in + MappingContext.getFieldInfoIfRecordType tpe ctx.typesContextInfo + |> Maybe.map processArgs + |> Maybe.withDefault Nothing + |> Maybe.map List.unzip + |> Maybe.map (\( ctorArgs, issues ) -> ( Scala.Apply caseClassReference ctorArgs, List.concat issues )) + |> Maybe.withDefault (errorValueAndIssue ("Record creation not converted: " ++ FQName.toString fullName)) + + _ -> + errorValueAndIssue "Record creation not converted" + + +mapListCreation : Type () -> List TypedValue -> ValueMappingContext -> ValueGenerationResult +mapListCreation tpe values ctx = + let + listOfRecordWithSimpleTypes = + typeRefIsListOf tpe (\innerTpe -> isTypeRefToRecordWithSimpleTypes innerTpe ctx.typesContextInfo) + in + if + listOfRecordWithSimpleTypes + && isFunctionClassificationReturningDataFrameExpressions ctx.currentFunctionClassification + then + let + ( mappedValues, valuesIssues ) = + values + |> List.map (\v -> mapLiteralListValue v ctx) + |> List.unzip + in + ( applySnowparkFunc "array_construct" mappedValues, List.concat valuesIssues ) + + else + case + ( getListTypeParameter tpe + |> Maybe.map (\t -> isTypeReferenceToSimpleTypesRecord t ctx.typesContextInfo) + |> Maybe.withDefault Nothing + , values + ) + of + ( Just ( path, name ), [] ) -> + ( Scala.Apply + (Scala.Select + (Scala.Ref path (Name.toTitleCase name)) + "createEmptyDataFrame" + ) + [ Scala.ArgValue Nothing (Scala.Variable "sfSession") ] + , [] + ) + + _ -> + let + ( mappedValues, valuesIssues ) = + values + |> List.map (\v -> mapValue v ctx) + |> List.unzip + in + ( Scala.Apply + (Scala.Variable "Seq") + (mappedValues |> List.map (Scala.ArgValue Nothing)) + , List.concat valuesIssues + ) + + +mapLiteralListValue : TypedValue -> ValueMappingContext -> ValueGenerationResult +mapLiteralListValue value ctx = + let + ( mappedValue, issues ) = + mapValue value ctx + in + case value of + Value.Variable _ _ -> + generateReplacementForDataFrameItemVariable mappedValue value ctx + |> Maybe.map (\result -> ( result, issues )) + |> Maybe.withDefault ( mappedValue, issues ) + + _ -> + ( mappedValue, issues ) + + +generateReplacementForDataFrameItemVariable : Scala.Value -> TypedValue -> ValueMappingContext -> Maybe Scala.Value +generateReplacementForDataFrameItemVariable replacement nameAccess ctx = + getFieldInfoIfRecordType (Value.valueAttribute nameAccess) ctx.typesContextInfo + |> Maybe.map + (\fields -> + let + args = + fields + |> List.map + (\( name, _ ) -> + Scala.Select replacement (Name.toCamelCase name) + ) + in + applySnowparkFunc "array_construct" args + ) + + +mapIfThenElse : TypedValue -> TypedValue -> TypedValue -> ValueMappingContext -> ValueGenerationResult +mapIfThenElse condition thenExpr elseExpr ctx = + let + ( mappedCondition, conditionIssues ) = + mapValue condition ctx + + ( mappedThen, thenIssues ) = + mapValue thenExpr ctx + + ( mappedElse, elseIssues ) = + mapValue elseExpr ctx + + whenCall = + Constants.applySnowparkFunc "when" [ mappedCondition, mappedThen ] + in + ( Scala.Apply (Scala.Select whenCall "otherwise") [ Scala.ArgValue Nothing mappedElse ] + , conditionIssues ++ thenIssues ++ elseIssues + ) diff --git a/src/Morphir/Snowpark/MapFunctionsMapping.elm b/src/Morphir/Snowpark/MapFunctionsMapping.elm new file mode 100644 index 000000000..66e37396a --- /dev/null +++ b/src/Morphir/Snowpark/MapFunctionsMapping.elm @@ -0,0 +1,1395 @@ +module Morphir.Snowpark.MapFunctionsMapping exposing + ( FunctionMappingTable + , MappingFunctionType + , basicsFunctionName + , checkForArgsToInline + , dataFrameMappings + , dictFunctionName + , listFunctionName + , mapFunctionsMapping + , mapUncurriedFunctionCall + , maybeFunctionName + , stringsFunctionName + ) + +import Dict exposing (Dict) +import Maybe.Extra as Extra +import Morphir.IR.FQName as FQName +import Morphir.IR.Name as Name +import Morphir.IR.Type as TypeIR exposing (Type) +import Morphir.IR.Value as ValueIR exposing (Pattern(..), TypedValue, Value(..), valueAttribute) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.AggregateMapping as AggregateMapping +import Morphir.Snowpark.Constants as Constants exposing (ValueGenerationResult, applySnowparkFunc) +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.JoinMapping as JoinMapping +import Morphir.Snowpark.LetMapping exposing (collectNestedLetDeclarations) +import Morphir.Snowpark.MappingContext as MappingContext + exposing + ( FunctionClassification(..) + , ValueMappingContext + , addReplacementForIdentifier + , getFieldInfoIfRecordType + , getLocalVariableIfDataFrameReference + , isAnonymousRecordWithSimpleTypes + , isBasicType + , isCandidateForDataFrame + , isFunctionReturningDataFrameExpressions + , isLocalFunctionName + , isTypeRefToRecordWithSimpleTypes + ) +import Morphir.Snowpark.Operatorsmaps exposing (mapOperator) +import Morphir.Snowpark.ReferenceUtils + exposing + ( errorValueAndIssue + , getExpressionForColumnsObject + , getInnerMaybeType + , getListTypeParameter + , getSourceTargetTypeIfFunctionType + , scalaPathToModule + ) +import Morphir.Snowpark.TypeRefMapping exposing (generateCastIfPossible, generateRecordTypeWrapperExpression, mapTypeReference) +import Morphir.Snowpark.UserDefinedFunctionMapping exposing (tryToConvertUserFunctionCall) +import Morphir.Snowpark.Utils exposing (collectMaybeList) +import Morphir.Value.Refactor exposing (inlineVariables) + + +type alias MappingFunctionType = + ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult + + +type alias FunctionMappingTable = + Dict FQName.FQName MappingFunctionType + + +listFunctionName : Name.Name -> FQName.FQName +listFunctionName simpleName = + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], simpleName ) + + +dictFunctionName : Name.Name -> FQName.FQName +dictFunctionName simpleName = + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], simpleName ) + + +maybeFunctionName : Name.Name -> FQName.FQName +maybeFunctionName simpleName = + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], simpleName ) + + +basicsFunctionName : Name.Name -> FQName.FQName +basicsFunctionName simpleName = + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], simpleName ) + + +stringsFunctionName : Name.Name -> FQName.FQName +stringsFunctionName simpleName = + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], simpleName ) + + +dataFrameMappings : FunctionMappingTable +dataFrameMappings = + [ ( listFunctionName [ "member" ], mapListMemberFunction ) + , ( listFunctionName [ "map" ], mapListMapFunction ) + , ( listFunctionName [ "filter" ], mapListFilterFunction ) + , ( listFunctionName [ "filter", "map" ], mapListFilterMapFunction ) + , ( listFunctionName [ "concat", "map" ], mapListConcatMapFunction ) + , ( listFunctionName [ "concat" ], mapListConcatFunction ) + , ( listFunctionName [ "sum" ], mapListSumFunction ) + , ( listFunctionName [ "length" ], mapListLengthFunction ) + , ( maybeFunctionName [ "just" ], mapJustFunction ) + , ( maybeFunctionName [ "map" ], mapMaybeMapFunction ) + , ( maybeFunctionName [ "with", "default" ], mapMaybeWithDefaultFunction ) + , ( basicsFunctionName [ "add" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "subtract" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "multiply" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "divide" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "integer", "divide" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "float", "divide" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "equal" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "not", "equal" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "greater", "than" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "less", "than" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "less", "than", "or", "equal" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "greater", "than", "or", "equal" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "and" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "or" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "mod", "by" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "sum", "of" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "average", "of" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "maximum", "of" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "minimum", "of" ], mapBasicsFunctionCall ) + , ( basicsFunctionName [ "not" ], mapNotFunctionCall ) + , ( basicsFunctionName [ "floor" ], mapFloorFunctionCall ) + , ( basicsFunctionName [ "min" ], mapMinMaxFunctionCall ( "min", "<" ) ) + , ( basicsFunctionName [ "max" ], mapMinMaxFunctionCall ( "max", ">" ) ) + , ( basicsFunctionName [ "to", "float" ], mapToFloatFunctionCall ) + , ( basicsFunctionName [ "compose", "right" ], mapComposeRightFunction ) + , ( stringsFunctionName [ "concat" ], mapStringConcatFunctionCall ) + , ( stringsFunctionName [ "length" ], mapStringLengthFunctionCall ) + , ( stringsFunctionName [ "to", "upper" ], mapStringCaseCall ( "String.toUpper", "upper" ) ) + , ( stringsFunctionName [ "to", "lower" ], mapStringCaseCall ( "String.toLower", "lower" ) ) + , ( stringsFunctionName [ "reverse" ], mapStringReverse ) + , ( stringsFunctionName [ "replace" ], mapStringReplace ) + , ( stringsFunctionName [ "starts", "with" ], mapStartsEndsWith ( "String.statsWith", "startswith" ) ) + , ( stringsFunctionName [ "ends", "with" ], mapStartsEndsWith ( "String.endsWith", "endswith" ) ) + , ( ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], [ "aggregate" ] ), mapAggregateFunction ) + ] + |> Dict.fromList + + +mapFunctionsMapping : TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapFunctionsMapping value mapValue ctx = + case value of + ValueIR.Apply _ function arg -> + mapUncurriedFunctionCall (ValueIR.uncurryApply function arg) mapValue dataFrameMappings ctx + + _ -> + errorValueAndIssue "Unsupported function mapping" + + +getFullNameIfReferencedElement : TypedValue -> Maybe FQName.FQName +getFullNameIfReferencedElement value = + case value of + ValueIR.Reference _ fullName -> + Just fullName + + ValueIR.Constructor _ fullName -> + Just fullName + + _ -> + Nothing + + +mapUncurriedFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> FunctionMappingTable -> ValueMappingContext -> ValueGenerationResult +mapUncurriedFunctionCall ( func, args ) mapValue mappings ctx = + let + funcNameIfAvailable = + getFullNameIfReferencedElement func + + mappingFunctionMaybe = + Extra.orElse + (funcNameIfAvailable + |> Maybe.andThen (\fullName -> Dict.get fullName mappings) + ) + (funcNameIfAvailable + |> Maybe.andThen (getInliningFunctionIfRequired ctx) + ) + in + case mappingFunctionMaybe of + Just mappingFunction -> + mappingFunction ( func, checkForArgsToInline ctx args ) mapValue ctx + + _ -> + tryToConvertUserFunctionCall ( func, args ) mapValue ctx + + +checkForArgsToInline : ValueMappingContext -> List TypedValue -> List TypedValue +checkForArgsToInline ctx args = + args + |> List.map + (\arg -> + case arg of + ValueIR.Lambda tpe pattern ((ValueIR.Apply _ ((ValueIR.Reference _ innerFuncName) as funcName) innerArg) as b) -> + Dict.get innerFuncName ctx.globalValuesToInline + |> Maybe.andThen + (\definition -> + let + ( _, innerArgs ) = + ValueIR.uncurryApply funcName innerArg + in + Just <| inlineFunctionCall innerArgs definition + ) + |> Maybe.map (ValueIR.Lambda tpe pattern) + |> Maybe.withDefault arg + + ValueIR.Apply tpe ((ValueIR.Reference (TypeIR.Function _ _ _) funcName) as funcReference) lastArg -> + Dict.get funcName ctx.globalValuesToInline + |> Maybe.map + (\definition -> + let + ( _, innerArgs ) = + ValueIR.uncurryApply funcReference lastArg + in + inlineFunctionCall innerArgs definition + ) + |> Maybe.withDefault arg + + ValueIR.Reference (TypeIR.Function _ _ _) funcName -> + Dict.get funcName ctx.globalValuesToInline + |> Maybe.map createLambdaFromType + |> Maybe.withDefault arg + + _ -> + arg + ) + + +createLambdaFromType : ValueIR.Definition () (TypeIR.Type ()) -> TypedValue +createLambdaFromType definition = + List.foldr + (\( name, _, aTpe ) current -> + ValueIR.Lambda + (TypeIR.Function () aTpe (ValueIR.valueAttribute current)) + (ValueIR.AsPattern aTpe (ValueIR.WildcardPattern aTpe) name) + current + ) + definition.body + definition.inputTypes + + +inlineFunctionCall : List TypedValue -> ValueIR.Definition () (TypeIR.Type ()) -> TypedValue +inlineFunctionCall args definition = + let + replacements = + List.map2 (\( paramName, _, _ ) arg -> ( paramName, arg )) definition.inputTypes args + |> Dict.fromList + in + inlineVariables replacements definition.body + + +getInliningFunctionIfRequired : ValueMappingContext -> FQName.FQName -> Maybe MappingFunctionType +getInliningFunctionIfRequired ctx name = + Dict.get name ctx.globalValuesToInline + |> Maybe.map + (\definition -> + \( _, args ) mapValue innerCtx -> + let + replacements = + List.map2 (\( paramName, _, _ ) arg -> ( paramName, arg )) definition.inputTypes args + |> Dict.fromList + + modifiedValue = + inlineVariables replacements definition.body + in + mapValue modifiedValue innerCtx + ) + + +mapListMemberFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListMemberFunction ( _, args ) mapValue ctx = + case args of + [ value, sourceRelation ] -> + let + ( variable, variableIssues ) = + mapValue value ctx + + ( applySequence, sourceRelationIssues ) = + mapValue sourceRelation ctx + + issues = + variableIssues ++ sourceRelationIssues + in + ( Scala.Apply (Scala.Select variable "in") [ Scala.ArgValue Nothing applySequence ], issues ) + + _ -> + errorValueAndIssue "`List.member` scenario not converted" + + +mapListConcatMapFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListConcatMapFunction ( _, args ) mapValue ctx = + case args of + [ filterAction, sourceRelation ] -> + generateForConcatMap filterAction sourceRelation ctx mapValue + + _ -> + errorValueAndIssue "List concatMap scenario not supported" + + +generateForConcatMap : TypedValue -> TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateForConcatMap action sourceRelation ctx mapValue = + let + ( mappedSourceRelation, sourceIssues ) = + mapValue sourceRelation ctx + in + case ( action, ValueIR.valueAttribute sourceRelation ) of + ( ValueIR.Lambda ((TypeIR.Function _ fromType toType) as lambdaFunctionType) (AsPattern _ _ lambdaParam) body, sourceRelationType ) -> + if + isCandidateForDataFrame sourceRelationType ctx.typesContextInfo + && isCandidateForDataFrame toType ctx.typesContextInfo + then + let + contextForBody = + getExpressionForColumnsObject fromType ctx + |> Maybe.map (\expr -> addReplacementForIdentifier lambdaParam expr ctx) + |> Maybe.withDefault ctx + + contextToUse = + { contextForBody | currentFunctionClassification = FromDfValuesToDfValues } + + ( mappedBody, bodyIssues ) = + mapValue body contextToUse + in + ( generateFlattenCallForConcatMap mappedBody mappedSourceRelation lambdaFunctionType ctx, bodyIssues ++ sourceIssues ) + + else + errorValueAndIssue "List.concatMap with lambda scenario not supported" + + ( functionExpr, sourceRelationType ) -> + if isCandidateForDataFrame sourceRelationType ctx.typesContextInfo then + getSourceTargetTypeIfFunctionType (ValueIR.valueAttribute functionExpr) + |> Maybe.andThen + (\( sourceType, targetType ) -> + if isCandidateForDataFrame targetType ctx.typesContextInfo then + MappingContext.getLocalVariableIfDataFrameReference sourceType ctx + + else + Nothing + ) + |> Maybe.andThen + (\localVar -> + let + ( mappedBodyExpr, bodyIssues ) = + mapValue functionExpr ctx + + mappedBody = + Scala.Apply mappedBodyExpr [ Scala.ArgValue Nothing (Scala.Variable localVar) ] + + functionExpressionType = + ValueIR.valueAttribute functionExpr + in + Just <| + ( generateFlattenCallForConcatMap mappedBody mappedSourceRelation functionExpressionType ctx, bodyIssues ++ sourceIssues ) + ) + |> Maybe.withDefault (errorValueAndIssue "List.concatMap scenario with function expression not supported") + + else + errorValueAndIssue "List.concatMap scenario not supported" + + +generateFlattenCallForConcatMap : Scala.Value -> Scala.Value -> Type () -> ValueMappingContext -> Scala.Value +generateFlattenCallForConcatMap mappedBody mappedSourceRelation lambdaFunctionType ctx = + let + selectArg = + Scala.Apply + (Scala.Select mappedBody "as") + [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "result")) ] + + flattenedDataFrame = + Scala.Apply + (Scala.Select + (Scala.Apply + (Scala.Select mappedSourceRelation "select") + [ Scala.ArgValue Nothing selectArg ] + ) + "flatten" + ) + [ Scala.ArgValue Nothing (applySnowparkFunc "col" [ Scala.Literal (Scala.StringLit "result") ]) ] + + finalProjection = + getSourceTargetTypeIfFunctionType lambdaFunctionType + |> Maybe.andThen (\( _, target ) -> getListTypeParameter target) + |> Maybe.andThen (\innerType -> generateProjectionForArrayColumnIfRequired innerType ctx flattenedDataFrame "value") + in + Maybe.withDefault flattenedDataFrame finalProjection + + +mapListConcatFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListConcatFunction ( _, args ) mapValue ctx = + case args of + [ elements ] -> + generateForListConcat elements ctx mapValue + + _ -> + errorValueAndIssue "List concat scenario not supported" + + +generateForListConcat : TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateForListConcat expr ctx mapValue = + case expr of + ValueIR.List (TypeIR.Reference _ _ [ TypeIR.Reference _ _ [ innerType ] ]) elements -> + if + isTypeRefToRecordWithSimpleTypes innerType ctx.typesContextInfo + && hasFunctionToDfOpertions elements ctx + then + let + ( convertedItems, itemsIssues ) = + elements + |> List.map (\item -> mapValue item ctx) + |> List.unzip + in + ( applySnowparkFunc "callBuiltin" [ Scala.Literal (Scala.StringLit "array_flatten"), applySnowparkFunc "array_construct" convertedItems ] + , List.concat itemsIssues + ) + + else + generateUnionAllWithMappedElements elements ctx mapValue + + _ -> + errorValueAndIssue "List.concat case not supported" + + +generateUnionAllWithMappedElements : List TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateUnionAllWithMappedElements elements ctx mapValue = + case elements of + first :: rest -> + let + ( firstMapped, firstIssues ) = + mapValue first ctx + in + rest + |> List.foldl + (\current ( result, issues ) -> + let + ( mappedValue, valueIssues ) = + mapValue current ctx + in + ( Scala.Apply (Scala.Select result "unionAll") [ Scala.ArgValue Nothing mappedValue ], issues ++ valueIssues ) + ) + ( firstMapped, firstIssues ) + + _ -> + errorValueAndIssue "List.concat case not supported" + + +hasFunctionToDfOpertions : List (Value a (Type ())) -> ValueMappingContext -> Bool +hasFunctionToDfOpertions listElements ctx = + case listElements of + (ValueIR.Apply _ f a) :: _ -> + case ValueIR.uncurryApply f a of + ( ValueIR.Reference _ fullName, _ ) -> + isFunctionReturningDataFrameExpressions fullName ctx + + _ -> + False + + _ -> + False + + +mapBasicsFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapBasicsFunctionCall ( name, args ) mapValue ctx = + case ( name, args ) of + ( ValueIR.Reference _ fullFuncName, [ left, right ] ) -> + mapForOperatorCall (FQName.getLocalName fullFuncName) left right mapValue ctx + + _ -> + errorValueAndIssue "Basics function scenario not supported" + + +mapForOperatorCall : Name.Name -> TypedValue -> TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapForOperatorCall optname left right mapValue ctx = + case ( optname, left, right ) of + ( [ "equal" ], _, ValueIR.Constructor _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "nothing" ] ) ) -> + let + ( mappedLeft, mappedLeftIssues ) = + mapValue left ctx + in + ( Scala.Select mappedLeft "is_null", mappedLeftIssues ) + + ( [ "not", "equal" ], _, ValueIR.Constructor _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "nothing" ] ) ) -> + let + ( mappedLeft, mappedLeftIssues ) = + mapValue left ctx + in + ( Scala.Select mappedLeft "is_not_null", mappedLeftIssues ) + + _ -> + let + ( leftValue, leftIssues ) = + mapValue left ctx + + ( rightValue, rightIssues ) = + mapValue right ctx + + operatorname = + mapOperator optname + + issues = + leftIssues ++ rightIssues + in + ( Scala.BinOp leftValue operatorname rightValue, issues ) + + +whenConditionElseValueCall : Scala.Value -> Scala.Value -> Scala.Value -> Scala.Value +whenConditionElseValueCall condition thenExpr elseExpr = + Scala.Apply (Scala.Select (Constants.applySnowparkFunc "when" [ condition, thenExpr ]) "otherwise") + [ Scala.ArgValue Nothing elseExpr ] + + +mapListSumFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListSumFunction ( _, args ) mapValue ctx = + case args of + [ elements ] -> + generateForListSum elements ctx mapValue + + _ -> + errorValueAndIssue "List sum scenario not supported" + + +mapListLengthFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListLengthFunction ( _, args ) mapValue ctx = + case args of + [ elements ] -> + if isCandidateForDataFrame (ValueIR.valueAttribute elements) ctx.typesContextInfo then + let + ( mappedCollection, collectionIssues ) = + mapValue elements ctx + in + ( Scala.Select mappedCollection "count", collectionIssues ) + + else + errorValueAndIssue "`List.length` scenario not supported" + + _ -> + errorValueAndIssue "`List.length` scenario not supported" + + +generateForListSum : TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateForListSum collection ctx mapValue = + case collection of + ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "map" ] )) _) sourceRelation -> + if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then + case mapValue collection ctx of + ( Scala.Apply col [ Scala.ArgValue argName projectedExpr ], issues ) -> + let + resultName = + Scala.Literal (Scala.StringLit "result") + + asCall = + Scala.Apply (Scala.Select projectedExpr "as") [ Scala.ArgValue Nothing resultName ] + + newSelect = + Scala.Apply col [ Scala.ArgValue argName asCall ] + + sumCall = + Constants.applySnowparkFunc "coalesce" + [ Constants.applySnowparkFunc "sum" [ Constants.applySnowparkFunc "col" [ resultName ] ] + , Constants.applySnowparkFunc "lit" [ Scala.Literal (Scala.IntegerLit 0) ] + ] + + selectResult = + Scala.Apply (Scala.Select newSelect "select") [ Scala.ArgValue Nothing sumCall ] + + methodToUse = + if isListOfInt (ValueIR.valueAttribute collection) then + "getInt" + + else + "getDouble" + in + ( Scala.Apply + (Scala.Select (Scala.Select (Scala.Select selectResult "first") "get") methodToUse) + [ Scala.ArgValue Nothing (Scala.Literal (Scala.IntegerLit 0)) ] + , issues + ) + + _ -> + errorValueAndIssue "Unsupported sum scenario" + + else + errorValueAndIssue "Unsupported `sum` scenario" + + _ -> + errorValueAndIssue "Unsupported `sum` scenario" + + +isListOfInt : Type () -> Bool +isListOfInt tpe = + MappingContext.typeRefIsListOf tpe (\t -> t == TypeIR.Reference () (basicsFunctionName [ "int" ]) []) + + +mapListFilterFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListFilterFunction ( _, args ) mapValue ctx = + case args of + [ filter, sourceRelation ] -> + generateForListFilter filter sourceRelation ctx mapValue + + _ -> + errorValueAndIssue "List filter scenario not supported" + + +generateForListFilter : TypedValue -> TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateForListFilter predicate sourceRelation ctx mapValue = + let + ( mappedSourceRelation, sourceRelationIssues ) = + mapValue sourceRelation ctx + + generateFilterCall ( functionExpr, issues ) = + ( Scala.Apply + (Scala.Select mappedSourceRelation "filter") + [ Scala.ArgValue Nothing functionExpr ] + , issues ++ sourceRelationIssues + ) + in + if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then + case predicate of + ValueIR.Lambda _ _ bodyExpr -> + generateFilterCall <| mapValue bodyExpr ctx + + ValueIR.Reference (TypeIR.Function _ fromType _) functionName -> + case ( isLocalFunctionName functionName ctx, generateRecordTypeWrapperExpression fromType ctx ) of + ( True, Just typeRefExpr ) -> + generateFilterCall <| + ( Scala.Apply (Scala.Ref (scalaPathToModule functionName) (functionName |> FQName.getLocalName |> Name.toCamelCase)) + [ Scala.ArgValue Nothing typeRefExpr ] + , [] + ) + + _ -> + errorValueAndIssue "Unsupported filter function with referenced function" + + ValueIR.Variable (TypeIR.Function _ fromType _) functionName -> + case generateRecordTypeWrapperExpression fromType ctx of + Just typeRefExpr -> + generateFilterCall <| + ( Scala.Apply (Scala.Variable (functionName |> Name.toCamelCase)) + [ Scala.ArgValue Nothing typeRefExpr ] + , [] + ) + + _ -> + errorValueAndIssue "Unsupported filter function with referenced function" + + (ValueIR.Apply ((TypeIR.Function _ fromTpe toType) as tpe) _ _) as call -> + let + newLambda = + ValueIR.Lambda + tpe + (ValueIR.AsPattern fromTpe (ValueIR.WildcardPattern fromTpe) [ "_t" ]) + (ValueIR.Apply toType call (ValueIR.Variable fromTpe [ "_t" ])) + in + generateForListFilter newLambda sourceRelation ctx mapValue + + _ -> + errorValueAndIssue "Unsupported filter function scenario" + + else + errorValueAndIssue "Unsupported filter scenario" + + +mapListFilterMapFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListFilterMapFunction ( _, args ) mapValue ctx = + case args of + [ filter, sourceRelation ] -> + generateForListFilterMap filter sourceRelation ctx mapValue + + _ -> + errorValueAndIssue "List filterMap scenario not supported" + + +generateForListFilterMap : TypedValue -> TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateForListFilterMap predicate sourceRelation ctx mapValue = + if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then + case predicate of + ValueIR.Lambda tpe _ binExpr -> + let + ( mappedBinExpr, issuesExpr ) = + mapValue binExpr ctx + + selectColumnAlias = + Scala.Apply (Scala.Select mappedBinExpr "as") [ Scala.ArgValue Nothing resultId ] + + ( mappedSourceRelation, sourceRelationIssues ) = + mapValue sourceRelation ctx + + selectCall = + Scala.Apply (Scala.Select mappedSourceRelation "select") [ Scala.ArgValue Nothing <| selectColumnAlias ] + + resultId = + Scala.Literal <| Scala.StringLit "result" + + isNotNullCall = + Scala.Select (Constants.applySnowparkFunc "col" [ resultId ]) "is_not_null" + + filterCall = + Scala.Apply (Scala.Select selectCall "filter") [ Scala.ArgValue Nothing isNotNullCall ] + in + ( getSourceTargetTypeIfFunctionType tpe + |> Maybe.andThen (\( _, target ) -> getInnerMaybeType target) + |> Maybe.andThen (\itemType -> generateProjectionForArrayColumnIfRequired itemType ctx filterCall "result") + |> Maybe.withDefault filterCall + , issuesExpr ++ sourceRelationIssues + ) + + _ -> + let + tpe = + ValueIR.valueAttribute predicate + + recordReference = + getListTypeParameter (valueAttribute sourceRelation) + |> Maybe.map (\t -> getLocalVariableIfDataFrameReference t ctx) + |> Maybe.withDefault Nothing + |> Maybe.map Scala.Variable + |> Maybe.withDefault (Scala.Literal Scala.NullLit) + + ( mappedPredicate, predicateIssues ) = + mapValue predicate ctx + + predicateApplication = + Scala.Apply mappedPredicate [ Scala.ArgValue Nothing recordReference ] + + selectColumnAlias = + Scala.Apply (Scala.Select predicateApplication "as") [ Scala.ArgValue Nothing resultId ] + + ( mappedSourceRelation, sourceRelationIssues ) = + mapValue sourceRelation ctx + + selectCall = + Scala.Apply (Scala.Select mappedSourceRelation "select") [ Scala.ArgValue Nothing <| selectColumnAlias ] + + resultId = + Scala.Literal <| Scala.StringLit "result" + + isNotNullCall = + Scala.Select (Constants.applySnowparkFunc "col" [ resultId ]) "is_not_null" + + filterCall = + Scala.Apply (Scala.Select selectCall "filter") [ Scala.ArgValue Nothing isNotNullCall ] + in + ( getSourceTargetTypeIfFunctionType tpe + |> Maybe.andThen (\( _, target ) -> getInnerMaybeType target) + |> Maybe.andThen (\itemType -> generateProjectionForArrayColumnIfRequired itemType ctx filterCall "result") + |> Maybe.withDefault filterCall + , predicateIssues ++ sourceRelationIssues + ) + + else + errorValueAndIssue "Unsupported filterMap scenario" + + +generateProjectionForArrayColumnIfRequired : Type () -> ValueMappingContext -> Scala.Value -> String -> Maybe Scala.Value +generateProjectionForArrayColumnIfRequired recordType ctx selectExpr resultColumnName = + let + resultColumn = + Constants.applySnowparkFunc "col" [ Scala.Literal (Scala.StringLit resultColumnName) ] + + generateFieldAccess : Int -> Scala.Value + generateFieldAccess idx = + Scala.Literal (Scala.IntegerLit idx) + + generateAsCall expr name = + Scala.Apply (Scala.Select expr "as") + [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit (Name.toCamelCase name))) ] + + resultFieldAccess idx = + Scala.Apply resultColumn [ Scala.ArgValue Nothing <| generateFieldAccess idx ] + + generateArrayUnpackingProjection : List ( Name.Name, Type () ) -> Scala.Value + generateArrayUnpackingProjection names = + Scala.Apply + (Scala.Select selectExpr "select") + (names + |> List.indexedMap (\i ( name, fType ) -> Scala.ArgValue Nothing <| generateAsCall (generateCastIfPossible ctx fType (resultFieldAccess i)) name) + ) + in + getFieldInfoIfRecordType recordType ctx.typesContextInfo + |> Maybe.map generateArrayUnpackingProjection + + +mapListMapFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapListMapFunction ( _, args ) mapValue ctx = + case args of + [ action, sourceRelation ] -> + generateForListMap action sourceRelation ctx mapValue + + _ -> + errorValueAndIssue "List map scenario not supported" + + +generateForListMap : TypedValue -> TypedValue -> ValueMappingContext -> Constants.MapValueType -> ValueGenerationResult +generateForListMap projection sourceRelation ctx mapValue = + if isCandidateForDataFrame (valueAttribute sourceRelation) ctx.typesContextInfo then + let + ( mappedSourceResult, issues ) = + mapValue sourceRelation ctx + in + case processMapWithLambdaWithRecordBody projection ctx mapValue of + Just ( arguments, argsIssues ) -> + ( Scala.Apply (Scala.Select mappedSourceResult "select") arguments, issues ++ List.concat argsIssues ) + + Nothing -> + case processMapWithUpdateRecordBody projection ctx mapValue mappedSourceResult of + Just ( result, iss ) -> + ( result, issues ++ List.concat iss ) + + _ -> + errorValueAndIssue "Unsupported map scenario for data frame parameter" + + else if isJoinFunction sourceRelation then + mapJoinFunction projection sourceRelation mapValue ctx + + else + errorValueAndIssue "Unsupported map scenario" + + +isJoinFunction : Value ta (Type ()) -> Bool +isJoinFunction value = + case value of + ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], name )) _) _) _ -> + if String.contains "Join" (Name.toCamelCase name) then + True + + else + False + + _ -> + False + + +processMapWithUpdateRecordBody : TypedValue -> ValueMappingContext -> Constants.MapValueType -> Scala.Value -> Maybe ( Scala.Value, List (List GenerationIssue) ) +processMapWithUpdateRecordBody functionExpr ctx mapValue mappedSourceRelation = + case functionExpr of + ValueIR.Lambda (TypeIR.Function _ _ returnType) (ValueIR.AsPattern _ _ _) (ValueIR.UpdateRecord _ expr fields) -> + if + isAnonymousRecordWithSimpleTypes returnType ctx.typesContextInfo + || isTypeRefToRecordWithSimpleTypes returnType ctx.typesContextInfo + then + let + ( nameValues, issues ) = + fields + |> Dict.toList + |> List.map + (\( name, value ) -> + let + ( mapped, innerIssues ) = + mapValue value ctx + in + ( ( name, mapped ), innerIssues ) + ) + |> List.unzip + + ( names, values ) = + nameValues + |> List.unzip + + nameArgs = + names + |> List.map (\name -> Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit (Name.toCamelCase name)))) + + valuesArgs = + values + |> List.map (Scala.ArgValue Nothing) + in + Just + ( Scala.Apply (Scala.Select mappedSourceRelation "withColumns") + [ Scala.ArgValue Nothing (Scala.Apply (Scala.Variable "Seq") nameArgs) + , Scala.ArgValue Nothing (Scala.Apply (Scala.Variable "Seq") valuesArgs) + ] + , issues + ) + + else + Nothing + + (ValueIR.Reference (TypeIR.Function _ fromType toType) _) as func -> + processListMapWithFunctionExpression mapValue func ctx fromType toType mappedSourceRelation + + (ValueIR.Apply (TypeIR.Function _ fromType toType) _ _) as func -> + processListMapWithFunctionExpression mapValue func ctx fromType toType mappedSourceRelation + + _ -> + Nothing + + +processListMapWithFunctionExpression : Constants.MapValueType -> TypedValue -> ValueMappingContext -> Type () -> Type () -> Scala.Value -> Maybe ( Scala.Value, List (List GenerationIssue) ) +processListMapWithFunctionExpression mapValue func ctx fromType toType mappedSourceRelation = + let + ( projCall, callIssues ) = + mapValue func ctx + in + getExpressionForColumnsObject fromType ctx + |> Maybe.andThen + (\columnsObject -> + let + asCall = + Scala.Apply + (Scala.Select + (Scala.Apply projCall [ Scala.ArgValue Nothing columnsObject ]) + "as" + ) + [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "result")) ] + + functionSelect = + Scala.Apply (Scala.Select mappedSourceRelation "select") + [ Scala.ArgValue Nothing asCall ] + + resultSelect = + generateProjectionForArrayColumnIfRequired + toType + ctx + functionSelect + "result" + in + resultSelect + |> Maybe.map (\e -> ( e, [ callIssues ] )) + ) + + +processMapWithLambdaWithRecordBody : TypedValue -> ValueMappingContext -> Constants.MapValueType -> Maybe ( List Scala.ArgValue, List (List GenerationIssue) ) +processMapWithLambdaWithRecordBody functionExpr ctx mapValue = + case functionExpr of + ValueIR.Lambda (TypeIR.Function _ _ returnType) (ValueIR.AsPattern _ _ _) (ValueIR.Record _ fields) -> + if + isAnonymousRecordWithSimpleTypes returnType ctx.typesContextInfo + || isTypeRefToRecordWithSimpleTypes returnType ctx.typesContextInfo + then + processMapRecordFields fields returnType ctx mapValue + + else + Nothing + + ValueIR.Lambda (TypeIR.Function _ _ returnType) (ValueIR.AsPattern _ _ _) expr -> + if isBasicType returnType then + let + ( mappedBody, mappedBodyIssues ) = + mapValue expr ctx + in + Just ( [ Scala.ArgValue Nothing mappedBody ], [ mappedBodyIssues ] ) + + else if + isAnonymousRecordWithSimpleTypes returnType ctx.typesContextInfo + || isTypeRefToRecordWithSimpleTypes returnType ctx.typesContextInfo + then + processMapWithLambdaBodyOfNonRecordLambda expr ctx mapValue + + else + Nothing + + ValueIR.FieldFunction _ _ -> + let + ( mappedFunctionExpr, mappedFunctionExprIssues ) = + mapValue functionExpr ctx + in + Just ( [ Scala.ArgValue Nothing mappedFunctionExpr ], [ mappedFunctionExprIssues ] ) + + _ -> + Nothing + + +processMapRecordFields : Dict Name.Name TypedValue -> Type () -> ValueMappingContext -> Constants.MapValueType -> Maybe ( List Scala.ArgValue, List (List GenerationIssue) ) +processMapRecordFields fields returnType ctx mapValue = + Just + (fields + |> getFieldsInCorrectOrder returnType ctx + |> List.map + (\( fieldName, value ) -> + ( Name.toCamelCase fieldName, mapValue value ctx ) + ) + |> List.map + (\( fieldName, ( value, issues ) ) -> + ( Scala.Apply + (Scala.Select (wrapBinaryOperationIfRequired value) "as") + [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit fieldName)) ] + , issues + ) + ) + |> List.map (\( value, issues ) -> ( Scala.ArgValue Nothing value, issues )) + |> List.unzip + ) + + +wrapBinaryOperationIfRequired : Scala.Value -> Scala.Value +wrapBinaryOperationIfRequired value = + case value of + Scala.BinOp _ _ _ -> Scala.Tuple [ value ] + _ -> + value + + +processMapWithLambdaBodyOfNonRecordLambda : TypedValue -> ValueMappingContext -> Constants.MapValueType -> Maybe ( List Scala.ArgValue, List (List GenerationIssue) ) +processMapWithLambdaBodyOfNonRecordLambda body ctx mapValue = + case body of + (ValueIR.LetDefinition _ _ _ _) as topDefinition -> + let + ( letDecls, letBodyExpr ) = + collectNestedLetDeclarations topDefinition [] + + ( newCtx, resultIssues ) = + letDecls + |> List.foldr + (\( name, def ) ( currentCtx, currentIssues ) -> + let + ( mappedDecl, issues ) = + mapValue def.body currentCtx + + newIssues = + currentIssues ++ issues + in + ( addReplacementForIdentifier name mappedDecl currentCtx + , newIssues + ) + ) + ( ctx, [] ) + in + case letBodyExpr of + ValueIR.Record recordType fields -> + processMapRecordFields fields recordType newCtx mapValue + |> Maybe.map (\( args, issuesLst ) -> ( args, issuesLst ++ [ resultIssues ] )) + + _ -> + Nothing + + _ -> + Nothing + + +getFieldsInCorrectOrder : Type () -> ValueMappingContext -> Dict Name.Name TypedValue -> List ( Name.Name, TypedValue ) +getFieldsInCorrectOrder originalType ctx fields = + case originalType of + TypeIR.Reference _ _ [] -> + getFieldInfoIfRecordType originalType ctx.typesContextInfo + |> Maybe.map + (\lst -> + collectMaybeList + (\( name, _ ) -> + Dict.get name fields + |> Maybe.map (\fieldvalue -> ( name, fieldvalue )) + ) + lst + ) + |> Maybe.withDefault Nothing + |> Maybe.withDefault (Dict.toList fields) + + _ -> + Dict.toList fields + + +mapJustFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapJustFunction ( _, args ) mapValue ctx = + case args of + [ justValue ] -> + mapValue justValue ctx + + _ -> + errorValueAndIssue "Maybe Just scenario not supported" + + +mapMaybeMapFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapMaybeMapFunction ( _, args ) mapValue ctx = + case args of + [ action, source ] -> + mapMaybeMapCall action source mapValue ctx + + _ -> + errorValueAndIssue "`Maybe.Just` scenario not supported" + + +mapMaybeMapCall : TypedValue -> TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapMaybeMapCall action maybeValue mapValue ctx = + case action of + ValueIR.Lambda _ (AsPattern _ (WildcardPattern _) lambdaParam) body -> + let + ( convertedValue, maybeValueIssues ) = + mapValue maybeValue ctx + + newReplacements = + Dict.fromList [ ( lambdaParam, convertedValue ) ] + + ( lambdaBody, lambdaIssues ) = + mapValue body { ctx | inlinedIds = Dict.union ctx.inlinedIds newReplacements } + + elseLiteral = + Constants.applySnowparkFunc "lit" [ Scala.Literal Scala.NullLit ] + + issues = + maybeValueIssues ++ lambdaIssues + in + ( whenConditionElseValueCall (Scala.Select convertedValue "is_not_null") lambdaBody elseLiteral, issues ) + + ValueIR.Reference _ _ -> + let + ( convertedValue, maybeValueIssues ) = + mapValue maybeValue ctx + + elseLiteral = + Constants.applySnowparkFunc "lit" [ Scala.Literal Scala.NullLit ] + + ( convertedFunctionApplication, funcApplicationIssues ) = + mapValue (ValueIR.Apply (ValueIR.valueAttribute maybeValue) action maybeValue) ctx + + issues = + maybeValueIssues ++ funcApplicationIssues + in + ( whenConditionElseValueCall (Scala.Select convertedValue "is_not_null") convertedFunctionApplication elseLiteral, issues ) + + _ -> + errorValueAndIssue "Unsupported `Maybe.map` scenario" + + +mapMaybeWithDefaultFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapMaybeWithDefaultFunction ( _, args ) mapValue ctx = + case args of + [ defaultValue, value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + + ( mappedDefaultValue, defaultValueIssues ) = + mapValue defaultValue ctx + + issues = + valueIssues ++ defaultValueIssues + in + ( Constants.applySnowparkFunc "coalesce" [ mappedValue, mappedDefaultValue ], issues ) + + _ -> + errorValueAndIssue "Maybe.withDefault scenario not supported" + + +mapAggregateFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapAggregateFunction ( _, args ) mapValue ctx = + case args of + [ ValueIR.Lambda _ (ValueIR.AsPattern _ _ firstParameterName) (ValueIR.Lambda _ lambdaPattern lambdaBody), ValueIR.Apply _ (ValueIR.Apply _ (ValueIR.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], [ "group", "by" ] )) (ValueIR.FieldFunction _ groupByCategory)) dfName ] -> + let + lambdaInfo = + { lambdaPattern = lambdaPattern + , lambdaBody = lambdaBody + , groupByName = groupByCategory + , firstParameter = firstParameterName + } + + variablesInfo = + AggregateMapping.processAggregateLambdaBody lambdaInfo ( mapValue, ctx ) + + ( mappedDfName, dfNameIssues ) = + mapValue dfName ctx + + collection = + Scala.Select mappedDfName "groupBy" + + dfGroupBy = + Scala.Apply collection [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit (Name.toCamelCase groupByCategory))) ] + + aggFunction = + Scala.Select dfGroupBy "agg" + + groupBySum = + Scala.Apply aggFunction variablesInfo.variable + + selectColumns = + Constants.transformToArgsValue <| List.map (\x -> Constants.applySnowparkFunc "col" [ x ]) variablesInfo.columnNameList + + select = + Scala.Apply (Scala.Select groupBySum "select") selectColumns + in + ( select, dfNameIssues ) + + _ -> + errorValueAndIssue "Aggregate scenario not supported" + + +mapJoinFunction : TypedValue -> TypedValue -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapJoinFunction projection joinValue mapValue ctx = + let + ( joinBody, joinBodyIssues ) = + JoinMapping.processJoinBody joinValue mapValue ctx + + ( joinProjection, joinProjectionIssues ) = + JoinMapping.processJoinProjection projection mapValue ctx + + select = + Scala.Select joinBody "select" + + argAlias = + Constants.transformToArgsValue joinProjection + in + ( Scala.Apply select argAlias, joinProjectionIssues ++ joinBodyIssues ) + + +mapNotFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ( Scala.Value, List GenerationIssue ) +mapNotFunctionCall ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, issues ) = + mapValue value ctx + in + ( Scala.UnOp "!" mappedValue, issues ) + + _ -> + ( Scala.Literal (Scala.StringLit "'Not' scenario not supported"), [ "'Not' scenario not supported" ] ) + + +mapStringConcatFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapStringConcatFunctionCall ( _, args ) mapValue ctx = + case args of + [ ValueIR.List _ values ] -> + let + ( mappedItems, itemsIssues ) = + values + |> List.map (\arg -> mapValue arg ctx) + |> List.unzip + + issues = + List.concat itemsIssues + in + ( Constants.applySnowparkFunc "concat" mappedItems, issues ) + + _ -> + errorValueAndIssue "'String.concat' scenario not supported" + + +mapComposeRightFunction : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapComposeRightFunction ( _, args ) mapValue ctx = + case args of + [ f1, f2 ] -> + let + ( mappedF1, value1Issues ) = + mapValue f1 ctx + + ( mappedF2, value2Issues ) = + mapValue f2 ctx + + firstElementTypeRef = + case ValueIR.valueAttribute f1 of + TypeIR.Function _ fromType _ -> + Just (mapTypeReference fromType ctx.currentFunctionClassification ctx.typesContextInfo) + + _ -> + Nothing + + issues = + value1Issues ++ value2Issues + in + ( Scala.Lambda [ ( "x", firstElementTypeRef ) ] + (Scala.Apply + mappedF2 + [ Scala.ArgValue Nothing (Scala.Apply mappedF1 [ Scala.ArgValue Nothing (Scala.Variable "x") ]) ] + ) + , issues + ) + + _ -> + errorValueAndIssue "`composeRight` scenario not supported" + + +mapMinMaxFunctionCall : ( String, String ) -> ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapMinMaxFunctionCall ( morphirName, operator ) ( _, args ) mapValue ctx = + case args of + [ value1, value2 ] -> + let + ( mappedValue1, value1Issues ) = + mapValue value1 ctx + + ( mappedValue2, value2Issues ) = + mapValue value2 ctx + + issues = + value1Issues ++ value2Issues + in + ( Scala.Apply + (Scala.Select + (Constants.applySnowparkFunc "when" [ Scala.BinOp mappedValue1 operator mappedValue2, mappedValue1 ]) + "otherwise" + ) + [ Scala.ArgValue Nothing mappedValue2 ] + , issues + ) + + _ -> + errorValueAndIssue ("`" ++ morphirName ++ " scenario not supported") + + +mapToFloatFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapToFloatFunctionCall ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Constants.applySnowparkFunc "as_double" [ mappedValue ], valueIssues ) + + _ -> + errorValueAndIssue "`toFloat` scenario not supported" + + +mapStringLengthFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapStringLengthFunctionCall ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Constants.applySnowparkFunc "length" [ mappedValue ], valueIssues ) + + _ -> + errorValueAndIssue "`String.length` scenario not supported" + + +mapFloorFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapFloorFunctionCall ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Constants.applySnowparkFunc "floor" [ mappedValue ], valueIssues ) + + _ -> + errorValueAndIssue "'floor' scenario not supported" + + +mapStringCaseCall : ( String, String ) -> ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapStringCaseCall ( morphirName, spName ) ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Constants.applySnowparkFunc spName [ mappedValue ], valueIssues ) + + _ -> + errorValueAndIssue ("`" ++ morphirName ++ "` scenario not supported") + + +mapStartsEndsWith : ( String, String ) -> ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapStartsEndsWith ( morphirName, spName ) ( _, args ) mapValue ctx = + case args of + [ prefixOrSuffix, str ] -> + let + ( mappedStr, strIssues ) = + mapValue str ctx + + ( mappedPrefixOrSuffix, prefixOrIssues ) = + mapValue prefixOrSuffix ctx + + issues = + strIssues ++ prefixOrIssues + in + ( Constants.applySnowparkFunc spName [ mappedStr, mappedPrefixOrSuffix ], issues ) + + _ -> + errorValueAndIssue ("`" ++ morphirName ++ "` scenario not supported") + + +mapStringReverse : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapStringReverse ( _, args ) mapValue ctx = + case args of + [ value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + in + ( Constants.applySnowparkFunc "callBuiltin" [ Scala.Literal (Scala.StringLit "reverse"), mappedValue ], valueIssues ) + + _ -> + errorValueAndIssue "`String.reverse` scenario not supported" + + +mapStringReplace : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapStringReplace ( _, args ) mapValue ctx = + case args of + [ toReplace, replacement, value ] -> + let + ( mappedValue, valueIssues ) = + mapValue value ctx + + ( mappedToReplace, toReplaceIssues ) = + mapValue toReplace ctx + + ( mappedReplacement, replacementIssues ) = + mapValue replacement ctx + + issues = + valueIssues ++ toReplaceIssues ++ replacementIssues + in + ( Constants.applySnowparkFunc "replace" [ mappedValue, mappedToReplace, mappedReplacement ], issues ) + + _ -> + errorValueAndIssue "`String.replace` scenario not supported" diff --git a/src/Morphir/Snowpark/MappingContext.elm b/src/Morphir/Snowpark/MappingContext.elm new file mode 100644 index 000000000..877769870 --- /dev/null +++ b/src/Morphir/Snowpark/MappingContext.elm @@ -0,0 +1,749 @@ +module Morphir.Snowpark.MappingContext exposing + ( FunctionClassification(..) + , GlobalDefinitionInformation + , MappingContextInfo + , ValueMappingContext + , addLocalDefinitions + , addReplacementForIdentifier + , emptyContext + , emptyValueMappingContext + , getFieldInfoIfRecordType + , getFunctionClassification + , getLocalVariableIfDataFrameReference + , getReplacementForIdentifier + , isAliasedBasicType + , isAnonymousRecordWithSimpleTypes + , isBasicType + , isCandidateForDataFrame + , isDataFrameFriendlyType + , isFunctionClassificationReturningDataFrameExpressions + , isFunctionReceivingDataFrameExpressions + , isFunctionReturningDataFrameExpressions + , isListOfDataFrameFriendlyType + , isLocalFunctionName + , isLocalVariableDefinition + , isRecordWithComplexTypes + , isRecordWithSimpleTypes + , isTypeAlias + , isTypeRefToRecordWithComplexTypes + , isTypeRefToRecordWithSimpleTypes + , isUnionTypeRefWithParams + , isUnionTypeRefWithoutParams + , isUnionTypeWithParams + , isUnionTypeWithoutParams + , processDistributionModules + , resolveTypeAlias + , typeRefIsListOf + ) + +{-| This module contains functions to collect information about type definitions in a distribution. +It classifies type definitions in the following kinds: + + - records with 'simple' or basic types (canditate to be treated as a dataframe) + - records containing other records + - Union types or Custom types with name-only constructors + - Union types or Custom types with complex constructors + - Builtin type aliases + | + +-} + +import Dict exposing (Dict) +import Morphir.IR.AccessControlled exposing (AccessControlled) +import Morphir.IR.FQName as FQName exposing (FQName) +import Morphir.IR.Module as Module exposing (ModuleName) +import Morphir.IR.Name exposing (Name) +import Morphir.IR.Package as Package +import Morphir.IR.Path as Path +import Morphir.IR.Type as Type exposing (Definition(..), Type(..)) +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Customization exposing (CustomizationOptions) +import Morphir.Snowpark.Utils exposing (tryAlternatives) +import Set exposing (Set) + + +type TypeDefinitionClassification a + = RecordWithSimpleTypes (List ( Name, Type a )) + | RecordWithComplexTypes (List ( Name, Type a )) + | UnionTypeWithoutParams + | UnionTypeWithParams + | TypeAlias (Type a) + + +type FunctionClassification + = FromDataFramesToValues + | FromDataFramesToDataFrames + | FromDfValuesToDfValues + | FromComplexValuesToDataFrames + | FromComplexToValues + | Unknown + + +type alias FunctionClassificationInformation = + Dict FQName FunctionClassification + + +type alias MappingContextInfo a = + Dict FQName (TypeClassificationState a) + + +type alias InlineValuesCollection = + Dict FQName (Value.Definition () (Type ())) + + +type alias GlobalDefinitionInformation a = + ( MappingContextInfo a, FunctionClassificationInformation, InlineValuesCollection ) + + +type alias ValueMappingContext = + { parameters : List Name + , localDefinitions : Set Name + , typesContextInfo : MappingContextInfo () + , inlinedIds : Dict Name Scala.Value + , packagePath : Path.Path + , dataFrameColumnsObjects : Dict FQName String + , functionClassificationInfo : FunctionClassificationInformation + , currentFunctionClassification : FunctionClassification + , globalValuesToInline : Dict FQName.FQName (Value.Definition () (Type.Type ())) + } + + +emptyValueMappingContext : ValueMappingContext +emptyValueMappingContext = + { parameters = [] + , localDefinitions = Set.empty + , inlinedIds = Dict.empty + , typesContextInfo = emptyContext + , packagePath = Path.fromString "default" + , dataFrameColumnsObjects = Dict.empty + , functionClassificationInfo = Dict.empty + , currentFunctionClassification = Unknown + , globalValuesToInline = Dict.empty + } + + +isLocalVariableDefinition : Name -> ValueMappingContext -> Bool +isLocalVariableDefinition name ctx = + Set.member name ctx.localDefinitions + + +addLocalDefinitions : List Name -> ValueMappingContext -> ValueMappingContext +addLocalDefinitions names ctx = + { ctx | localDefinitions = Set.union (Set.fromList names) ctx.localDefinitions } + + +isFunctionReturningDataFrameExpressions : FQName -> ValueMappingContext -> Bool +isFunctionReturningDataFrameExpressions name ctx = + Dict.get name ctx.functionClassificationInfo + |> Maybe.map isFunctionClassificationReturningDataFrameExpressions + |> Maybe.withDefault False + + +isFunctionClassificationReturningDataFrameExpressions : FunctionClassification -> Bool +isFunctionClassificationReturningDataFrameExpressions classfication = + case classfication of + FromDfValuesToDfValues -> + True + + _ -> + False + + +isFunctionReceivingDataFrameExpressions : FQName -> ValueMappingContext -> Bool +isFunctionReceivingDataFrameExpressions name ctx = + Dict.get name ctx.functionClassificationInfo + |> Maybe.map isFunctionClassificationReceivingDataFrameExpressions + |> Maybe.withDefault False + + +isFunctionClassificationReceivingDataFrameExpressions : FunctionClassification -> Bool +isFunctionClassificationReceivingDataFrameExpressions classfication = + case classfication of + FromDfValuesToDfValues -> + True + + FromDataFramesToValues -> + True + + FromDataFramesToDataFrames -> + True + + _ -> + False + + +getReplacementForIdentifier : Name -> ValueMappingContext -> Maybe Scala.Value +getReplacementForIdentifier name ctx = + Dict.get name ctx.inlinedIds + + +addReplacementForIdentifier : Name -> Scala.Value -> ValueMappingContext -> ValueMappingContext +addReplacementForIdentifier name value ctx = + let + newReplacedIds = + Dict.insert name value ctx.inlinedIds + in + { ctx | inlinedIds = newReplacedIds } + + +emptyContext : MappingContextInfo a +emptyContext = + Dict.empty + + +isLocalFunctionName : FQName -> ValueMappingContext -> Bool +isLocalFunctionName name ctx = + FQName.getPackagePath name == ctx.packagePath + + +isRecordWithSimpleTypes : FQName -> MappingContextInfo () -> Bool +isRecordWithSimpleTypes name ctx = + case Dict.get name ctx of + Just (TypeClassified (RecordWithSimpleTypes _)) -> + True + + _ -> + False + + +isTypeRefToRecordWithSimpleTypes : Type () -> MappingContextInfo () -> Bool +isTypeRefToRecordWithSimpleTypes tpe ctx = + typeRefNamePredicate tpe isRecordWithSimpleTypes ctx + + +isTypeRefToRecordWithComplexTypes : Type a -> MappingContextInfo a -> Bool +isTypeRefToRecordWithComplexTypes tpe ctx = + typeRefNamePredicate tpe isRecordWithComplexTypes ctx + + +isRecordWithComplexTypes : FQName -> MappingContextInfo a -> Bool +isRecordWithComplexTypes name ctx = + case Dict.get name ctx of + Just (TypeClassified (RecordWithComplexTypes _)) -> + True + + _ -> + False + + +isUnionTypeWithoutParams : FQName -> MappingContextInfo a -> Bool +isUnionTypeWithoutParams name ctx = + case Dict.get name ctx of + Just (TypeClassified UnionTypeWithoutParams) -> + True + + _ -> + False + + +typeRefNamePredicate : Type a -> (FQName -> MappingContextInfo a -> Bool) -> MappingContextInfo a -> Bool +typeRefNamePredicate tpe predicateToCheckOnName ctx = + case tpe of + Type.Reference _ name _ -> + predicateToCheckOnName name ctx + + _ -> + False + + +isUnionTypeRefWithoutParams : Type a -> MappingContextInfo a -> Bool +isUnionTypeRefWithoutParams tpe ctx = + typeRefNamePredicate tpe isUnionTypeWithoutParams ctx + + +isUnionTypeRefWithParams : Type a -> MappingContextInfo a -> Bool +isUnionTypeRefWithParams tpe ctx = + typeRefNamePredicate tpe isUnionTypeWithParams ctx + + +isUnionTypeWithParams : FQName -> MappingContextInfo a -> Bool +isUnionTypeWithParams name ctx = + case Dict.get name ctx of + Just (TypeClassified UnionTypeWithParams) -> + True + + _ -> + False + + +isTypeAlias : FQName -> MappingContextInfo a -> Bool +isTypeAlias name ctx = + case Dict.get name ctx of + Just (TypeClassified (TypeAlias _)) -> + True + + _ -> + False + + +resolveTypeAlias : FQName -> MappingContextInfo a -> Maybe (Type a) +resolveTypeAlias name ctx = + case Dict.get name ctx of + Just (TypeClassified (TypeAlias t)) -> + Just t + + _ -> + Nothing + + +isCandidateForDataFrame : Type () -> MappingContextInfo () -> Bool +isCandidateForDataFrame typeRef ctx = + case typeRef of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] ) [ Type.Reference _ itemTypeName [] ] -> + isRecordWithSimpleTypes itemTypeName ctx + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] ) [ Type.Record _ fields ] -> + fields + |> List.all (\{ tpe } -> isDataFrameFriendlyType tpe ctx) + + Type.Reference _ name [] -> + resolveTypeAlias name ctx + |> Maybe.map (\resolvedType -> isCandidateForDataFrame resolvedType ctx) + |> Maybe.withDefault False + + _ -> + False + + +isListOfDataFrameFriendlyType : Type () -> MappingContextInfo () -> Bool +isListOfDataFrameFriendlyType typeRef ctx = + case typeRef of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] ) [ tpe ] -> + isDataFrameFriendlyType tpe ctx + + _ -> + False + + +getLocalVariableIfDataFrameReference : Type.Type () -> ValueMappingContext -> Maybe String +getLocalVariableIfDataFrameReference tpe ctx = + case tpe of + Type.Reference _ typeName _ -> + Dict.get typeName ctx.dataFrameColumnsObjects + + _ -> + Nothing + + +isAnonymousRecordWithSimpleTypes : Type.Type () -> MappingContextInfo () -> Bool +isAnonymousRecordWithSimpleTypes tpe ctx = + case tpe of + Type.Record _ fields -> + List.all (\field -> isDataFrameFriendlyType field.tpe ctx) fields + + _ -> + False + + +type TypeClassificationState a + = TypeClassified (TypeDefinitionClassification a) + | TypeWithPendingClassification (Maybe (Type a)) + | TypeNotClassified + + +classifyType : Type.Definition () -> MappingContextInfo () -> TypeClassificationState () +classifyType typeDefinition ctx = + case typeDefinition of + Type.TypeAliasDefinition _ t -> + classifyActualType t ctx + + Type.CustomTypeDefinition _ { value } -> + let + zeroArgConstructors = + value + |> Dict.values + |> List.all (\args -> 0 == List.length args) + in + if zeroArgConstructors then + TypeClassified UnionTypeWithoutParams + + else + TypeClassified UnionTypeWithParams + + +isBasicType : Type a -> Bool +isBasicType tpe = + case tpe of + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], _ ) _ -> + True + + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], _ ) _ -> + True + + _ -> + False + + +isSdkType : Type a -> Bool +isSdkType tpe = + case tpe of + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], _, _ ) _ -> + True + + _ -> + False + + +isAliasedBasicType : Type a -> MappingContextInfo a -> Bool +isAliasedBasicType tpe ctx = + case tpe of + Type.Reference _ fqname [] -> + Maybe.withDefault False (Dict.get fqname ctx |> Maybe.map isAliasedBasicTypeWithPendingClassification) + + _ -> + False + + +isAliasedBasicTypeWithPendingClassification : TypeClassificationState a -> Bool +isAliasedBasicTypeWithPendingClassification transitoryTypeClassification = + transitoryTypeClassification + |> aliasedBasicTypeWithPendingClassification + |> Maybe.map isBasicType + |> Maybe.withDefault False + + +aliasedBasicTypeWithPendingClassification : TypeClassificationState a -> Maybe (Type a) +aliasedBasicTypeWithPendingClassification transitoryTypeClassification = + case transitoryTypeClassification of + TypeClassified (TypeAlias tpe) -> + Just tpe + + _ -> + Nothing + + +isUnionType : Type a -> MappingContextInfo a -> Bool +isUnionType tpe ctx = + let + isUnionTypePred = + \t -> + case t of + TypeClassified UnionTypeWithoutParams -> + True + + TypeClassified UnionTypeWithParams -> + True + + _ -> + False + in + case tpe of + Reference _ name _ -> + Dict.get name ctx + |> Maybe.map isUnionTypePred + |> Maybe.withDefault False + + _ -> + False + + +isAliasOfBasicType : Type a -> MappingContextInfo a -> Bool +isAliasOfBasicType tpe ctx = + case tpe of + Reference _ name _ -> + Dict.get name ctx + |> Maybe.map isAliasedBasicTypeWithPendingClassification + |> Maybe.withDefault False + + _ -> + False + + +isAliasOfDataFrameFriendlyType : Type a -> MappingContextInfo a -> Bool +isAliasOfDataFrameFriendlyType tpe ctx = + case tpe of + Reference _ name _ -> + Dict.get name ctx + |> Maybe.map aliasedBasicTypeWithPendingClassification + |> Maybe.withDefault Nothing + |> Maybe.map (\x -> isDataFrameFriendlyType x ctx) + |> Maybe.withDefault False + + _ -> + False + + +typeRefIsMaybeOf : Type a -> (Type a -> Bool) -> Bool +typeRefIsMaybeOf tpe predicate = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ typeArg ] -> + predicate typeArg + + _ -> + False + + +typeRefIsListOf : Type a -> (Type a -> Bool) -> Bool +typeRefIsListOf tpe predicate = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] ) [ typeArg ] -> + predicate typeArg + + _ -> + False + + +isMaybeOfDataFrameFriendlyType : Type a -> MappingContextInfo a -> Bool +isMaybeOfDataFrameFriendlyType tpe ctx = + typeRefIsMaybeOf tpe (\innerTpe -> isDataFrameFriendlyType innerTpe ctx) + + +isDataFrameFriendlyType : Type a -> MappingContextInfo a -> Bool +isDataFrameFriendlyType tpe ctx = + isBasicType tpe + || isUnionType tpe ctx + || isAliasOfDataFrameFriendlyType tpe ctx + || isMaybeOfDataFrameFriendlyType tpe ctx + + +getFieldInfoIfRecordType : Type a -> MappingContextInfo a -> Maybe (List ( Name, Type a )) +getFieldInfoIfRecordType tpe ctx = + case tpe of + Reference _ typeName _ -> + case Dict.get typeName ctx of + Just (TypeClassified (RecordWithSimpleTypes fieldInfo)) -> + Just fieldInfo + + Just (TypeClassified (RecordWithComplexTypes fieldInfo)) -> + Just fieldInfo + + _ -> + Nothing + + Record _ fields -> + Just <| List.map (\field -> ( field.name, field.tpe )) fields + + _ -> + Nothing + + +getFunctionClassification : FQName -> FunctionClassificationInformation -> FunctionClassification +getFunctionClassification fullName functionsInfo = + Dict.get fullName functionsInfo + |> Maybe.withDefault Unknown + + +classifyActualType : Type a -> MappingContextInfo a -> TypeClassificationState a +classifyActualType tpe ctx = + case tpe of + Record _ members -> + if List.all (\t -> isDataFrameFriendlyType t.tpe ctx) members then + TypeClassified (RecordWithSimpleTypes (members |> List.map (\field -> ( field.name, field.tpe )))) + + else + TypeWithPendingClassification (Just tpe) + + Reference _ _ _ -> + if + isBasicType tpe + || isUnionType tpe ctx + || isAliasOfDataFrameFriendlyType tpe ctx + || isSdkType tpe + then + TypeClassified (TypeAlias tpe) + + else + TypeWithPendingClassification (Just tpe) + + _ -> + TypeNotClassified + + +simpleName packagePath modName name = + FQName.fQName packagePath modName name + + +processFunctionDefinition : Value.Definition () (Type ()) -> MappingContextInfo () -> FunctionClassification +processFunctionDefinition definition ctx = + let + inputTypes = + definition.inputTypes |> List.map (\( _, _, third ) -> third) + in + tryAlternatives + [ \_ -> + if + List.all (\tpe -> isDataFrameFriendlyType tpe ctx) inputTypes + && isDataFrameFriendlyType definition.outputType ctx + then + Just FromDfValuesToDfValues + + else + Nothing + , \_ -> + if + List.all + (\tpe -> + isDataFrameFriendlyType tpe ctx + || isTypeRefToRecordWithSimpleTypes tpe ctx + || isTypeRefToRecordWithSimpleTypes tpe ctx + || typeRefIsMaybeOf tpe (\t -> isTypeRefToRecordWithSimpleTypes t ctx) + ) + inputTypes + && (isDataFrameFriendlyType definition.outputType ctx + || isTypeRefToRecordWithSimpleTypes definition.outputType ctx + || typeRefIsMaybeOf definition.outputType (\t -> isTypeRefToRecordWithSimpleTypes t ctx || isAnonymousRecordWithSimpleTypes t ctx) + ) + then + Just FromDfValuesToDfValues + + else + Nothing + , \_ -> + if + List.all + (\tpe -> + isDataFrameFriendlyType tpe ctx + || typeRefIsListOf tpe (\listElementType -> isDataFrameFriendlyType listElementType ctx) + || isTypeRefToRecordWithSimpleTypes tpe ctx + ) + inputTypes + && typeRefIsListOf definition.outputType (\t -> isTypeRefToRecordWithSimpleTypes t ctx) + then + Just FromDfValuesToDfValues + + else + Nothing + , \_ -> + if + List.any (\tpe -> isCandidateForDataFrame tpe ctx) inputTypes + && not (List.any (\tpe -> isTypeRefToRecordWithComplexTypes tpe ctx) inputTypes) + && isDataFrameFriendlyType definition.outputType ctx + then + Just FromDataFramesToValues + + else + Nothing + , \_ -> + if + List.any (\tpe -> isCandidateForDataFrame tpe ctx) inputTypes + && not (List.any (\tpe -> isTypeRefToRecordWithComplexTypes tpe ctx) inputTypes) + && isCandidateForDataFrame definition.outputType ctx + then + Just FromDataFramesToDataFrames + + else + Nothing + , \_ -> + if + List.any (\tpe -> isTypeRefToRecordWithComplexTypes tpe ctx) inputTypes + && isCandidateForDataFrame definition.outputType ctx + then + Just FromComplexValuesToDataFrames + + else + Nothing + , \_ -> + if List.any (\tpe -> isTypeRefToRecordWithComplexTypes tpe ctx) inputTypes then + Just FromComplexToValues + + else + Nothing + ] + |> Maybe.withDefault Unknown + + +processModuleDefinition : Package.PackageName -> ModuleName -> MappingContextInfo () -> AccessControlled (Module.Definition () (Type ())) -> MappingContextInfo () +processModuleDefinition packagePath modulePath currentResult moduleDefinition = + moduleDefinition.value.types + |> Dict.toList + |> List.map (\( name, acc ) -> ( name, acc.value.value )) + |> List.map (\( name, typeDefinition ) -> ( simpleName packagePath modulePath name, classifyType typeDefinition currentResult )) + |> Dict.fromList + |> Dict.union currentResult + + +processSecondPassOnType : FQName -> TypeClassificationState () -> MappingContextInfo () -> MappingContextInfo () +processSecondPassOnType name typeClassification ctx = + case typeClassification of + TypeClassified _ -> + ctx + + TypeWithPendingClassification (Just tpe) -> + case classifyActualType tpe ctx of + TypeClassified newType -> + Dict.update name (\_ -> Just (TypeClassified newType)) ctx + + -- If we could not classify a record after the second pass classify it as 'complex' + TypeWithPendingClassification (Just (Record _ members)) -> + Dict.update name (\_ -> Just (TypeClassified (RecordWithComplexTypes (members |> List.map (\field -> ( field.name, field.tpe )))))) ctx + + _ -> + ctx + + _ -> + ctx + + +processDistributionModules : Package.PackageName -> Package.Definition () (Type ()) -> CustomizationOptions -> GlobalDefinitionInformation () +processDistributionModules packagePath package customizationOptions = + let + moduleList = + package.modules + |> Dict.toList + + firstPass = + moduleList + |> List.foldr + (\( modName, modDef ) curretnResult -> processModuleDefinition packagePath modName curretnResult modDef) + Dict.empty + + secondPass = + firstPass + |> Dict.foldr (\key value result -> processSecondPassOnType key value result) firstPass + + functionsClassifed = + moduleList + |> List.concatMap + (\( modName, modDef ) -> + modDef.value.values + |> Dict.toList + |> List.map (\( valueName, value ) -> ( modName, valueName, value.value.value )) + ) + |> List.filter (\( modName, valueName, value ) -> 0 < List.length value.inputTypes) + |> List.foldl + (\( modName, valueName, value ) current -> + let + fullFunctionName = + FQName.fQName packagePath modName valueName + + classfication = + processFunctionDefinition value secondPass + in + Dict.insert fullFunctionName classfication current + ) + Dict.empty + + valuesToInline = + collectValuesToInline customizationOptions.functionsToInline package.modules + in + ( secondPass, functionsClassifed, valuesToInline ) + + +collectValuesToInline : Set FQName -> Dict ModuleName (AccessControlled (Module.Definition () (Type ()))) -> Dict FQName (Value.Definition () (Type ())) +collectValuesToInline namesToInline modules = + collectingValuesToInline (Set.toList namesToInline) modules Dict.empty + + +collectingValuesToInline : List FQName -> Dict ModuleName (AccessControlled (Module.Definition () (Type ()))) -> Dict FQName (Value.Definition () (Type ())) -> Dict FQName (Value.Definition () (Type ())) +collectingValuesToInline namesToInline modules current = + case namesToInline of + first :: rest -> + let + newDict = + case Dict.get (FQName.getModulePath first) modules of + Just mod -> + case Dict.get (FQName.getLocalName first) mod.value.values of + Just { value } -> + Dict.insert first value.value current + + _ -> + current + + _ -> + current + in + collectingValuesToInline rest modules newDict + + _ -> + current diff --git a/src/Morphir/Snowpark/Operatorsmaps.elm b/src/Morphir/Snowpark/Operatorsmaps.elm new file mode 100644 index 000000000..a8e6f516c --- /dev/null +++ b/src/Morphir/Snowpark/Operatorsmaps.elm @@ -0,0 +1,65 @@ +module Morphir.Snowpark.Operatorsmaps exposing (mapOperator) + + +mapOperator : List String -> String +mapOperator name = + case name of + [ "add" ] -> + "+" + + [ "subtract" ] -> + "-" + + [ "multiply" ] -> + "*" + + [ "divide" ] -> + "/" + + [ "integer", "divide" ] -> + "/" + + [ "float", "divide" ] -> + "/" + + [ "equal" ] -> + "===" + + [ "not", "equal" ] -> + "=!=" + + [ "greater", "than" ] -> + ">" + + [ "less", "than" ] -> + "<" + + [ "less", "than", "or", "equal" ] -> + "<=" + + [ "greater", "than", "or", "equal" ] -> + ">=" + + [ "and" ] -> + "&&" + + [ "or" ] -> + "||" + + [ "mod", "by" ] -> + "%" + + [ "sum", "of" ] -> + "sum" + + [ "average", "of" ] -> + "avg" + + [ "maximum", "of" ] -> + "max" + + [ "minimum", "of" ] -> + "min" + + _ -> + "UnsupportedOperator" diff --git a/src/Morphir/Snowpark/PatternMatchMapping.elm b/src/Morphir/Snowpark/PatternMatchMapping.elm new file mode 100644 index 000000000..58b44c391 --- /dev/null +++ b/src/Morphir/Snowpark/PatternMatchMapping.elm @@ -0,0 +1,514 @@ +module Morphir.Snowpark.PatternMatchMapping exposing (PatternMatchValues, mapPatternMatch) + +{-| Generation for `PatternMatch` expressions +-} + +import Dict +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal exposing (Literal) +import Morphir.IR.Name as Name +import Morphir.IR.Type as Type exposing (Type) +import Morphir.IR.Value as Value exposing (Pattern(..), TypedValue, Value) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants as Constants exposing (ValueGenerationResult, applySnowparkFunc) +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.MappingContext + exposing + ( ValueMappingContext + , addReplacementForIdentifier + , isUnionTypeRefWithParams + , isUnionTypeRefWithoutParams + ) +import Morphir.Snowpark.ReferenceUtils + exposing + ( getCustomTypeParameterFieldAccess + , mapLiteral + , scalaReferenceToUnionTypeCase + ) +import Morphir.Snowpark.Utils exposing (collectMaybeList, tryAlternatives) + + +type alias PatternMatchValues = + ( Type (), TypedValue, List ( Pattern (Type ()), TypedValue ) ) + + +equalExpr : Scala.Value -> Scala.Value -> Scala.Value +equalExpr left right = + Scala.BinOp left "===" right + + +createChainOfWhenCalls : ( Scala.Value, Scala.Value ) -> List ( Scala.Value, Scala.Value ) -> Scala.Value +createChainOfWhenCalls ( firstCondition, firstValue ) restConditionActionPairs = + List.foldl + (\( condition, resultExpr ) accumulated -> + Scala.Apply (Scala.Select accumulated "when") [ Scala.ArgValue Nothing condition, Scala.ArgValue Nothing resultExpr ] + ) + (applySnowparkFunc "when" [ firstCondition, firstValue ]) + restConditionActionPairs + + +createChainOfWhenWithOtherwise : ( Scala.Value, Scala.Value ) -> List ( Scala.Value, Scala.Value ) -> Scala.Value -> Scala.Value +createChainOfWhenWithOtherwise first restConditionActionPairs defaultValue = + let + whenCalls = + createChainOfWhenCalls first restConditionActionPairs + in + Scala.Apply (Scala.Select whenCalls "otherwise") [ Scala.ArgValue Nothing defaultValue ] + + +createChainOfWhenWithOptionalOtherwise : ( Scala.Value, Scala.Value ) -> List ( Scala.Value, Scala.Value ) -> Maybe Scala.Value -> Scala.Value +createChainOfWhenWithOptionalOtherwise first restConditionActionPairs maybeDefaultValue = + case maybeDefaultValue of + Just defaultValue -> + createChainOfWhenWithOtherwise first restConditionActionPairs defaultValue + + _ -> + createChainOfWhenCalls first restConditionActionPairs + + +mapPatternMatch : PatternMatchValues -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +mapPatternMatch ( tpe, expr, cases ) mapValue ctx = + let + ( mappedTopExpr, topExprIssues ) = + mapValue expr ctx + in + case classifyScenario expr cases ctx of + LiteralsWithDefault (( firstLit, firstExpr ) :: rest) defaultValue -> + let + compareWithExpr = + equalExpr mappedTopExpr + + litExpr = + mapLiteral () firstLit + + ( restPairs, restIssues ) = + rest + |> List.map (\( lit, val ) -> ( lit, mapValue val ctx )) + |> List.map (\( lit, ( mappedVal, issues ) ) -> ( ( compareWithExpr (mapLiteral () lit), mappedVal ), issues )) + |> List.unzip + + ( mappedDefaultValue, defaultValueIssues ) = + mapValue defaultValue ctx + + ( mappedFirstExpr, firstExprIssues ) = + mapValue firstExpr ctx + in + ( createChainOfWhenWithOtherwise ( compareWithExpr litExpr, mappedFirstExpr ) restPairs mappedDefaultValue + , topExprIssues ++ List.concat restIssues ++ defaultValueIssues ++ firstExprIssues + ) + + UnionTypesWithoutParams (( firstConstr, firstExpr ) :: rest) maybeDefaultValue -> + let + compareWithExpr = + equalExpr mappedTopExpr + + ( restPairs, restIssues ) = + rest + |> List.map (\( lit, val ) -> ( lit, mapValue val ctx )) + |> List.map (\( constr, ( val, issues ) ) -> ( ( compareWithExpr constr, val ), issues )) + |> List.unzip + + ( mappedFirstExpr, firstExprIssues ) = + mapValue firstExpr ctx + + ( mappedDefaultMaybe, defaultMaybeIssues ) = + mapMaybeValue maybeDefaultValue ctx mapValue + in + ( createChainOfWhenWithOptionalOtherwise ( compareWithExpr firstConstr, mappedFirstExpr ) restPairs mappedDefaultMaybe + , topExprIssues ++ List.concat restIssues ++ defaultMaybeIssues ++ firstExprIssues + ) + + UnionTypesWithParams (( firstConstr, firstNestedPatternInfo, firstExpr ) :: rest) maybeDefaultValue -> + let + compareWithExpr : Name.Name -> Scala.Value + compareWithExpr = + \name -> + equalExpr (Scala.Apply mappedTopExpr [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "__tag")) ]) + (applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit (Name.toTitleCase name)) ]) + + ( restPairs, restIssues ) = + rest + |> List.map + (\( constr, nestedPatternsInfos, val ) -> + ( constr + , nestedPatternsInfos + , mapValue val (addBindingReplacementsToContext ctx nestedPatternsInfos mappedTopExpr) + ) + ) + |> List.map (\( constr, nestedPatternsInfos, ( val, issues ) ) -> ( ( generateNestedPatternsCondition nestedPatternsInfos mappedTopExpr (compareWithExpr constr), val ), issues )) + |> List.unzip + + ( mappedDefaultMaybe, defaultMaybeIssues ) = + mapMaybeValue maybeDefaultValue ctx mapValue + + ( mappedFirstExpr, firstExprIssues ) = + mapValue firstExpr (addBindingReplacementsToContext ctx firstNestedPatternInfo mappedTopExpr) + + firstCondition = + generateNestedPatternsCondition firstNestedPatternInfo mappedTopExpr (compareWithExpr firstConstr) + in + ( createChainOfWhenWithOptionalOtherwise ( firstCondition, mappedFirstExpr ) restPairs mappedDefaultMaybe + , defaultMaybeIssues ++ topExprIssues ++ List.concat restIssues ++ firstExprIssues + ) + + MaybeCase ( justVariable, justExpr ) nothingExpr -> + let + ( generatedJustExpr, justIssues ) = + mapValue justExpr (Maybe.withDefault ctx (Maybe.map (\varName -> { ctx | inlinedIds = Dict.insert varName mappedTopExpr ctx.inlinedIds }) justVariable)) + + ( generatedNothingExpr, nothingIssues ) = + mapValue nothingExpr ctx + in + ( createChainOfWhenWithOtherwise ( Scala.Select mappedTopExpr "is_not_null", generatedJustExpr ) [] generatedNothingExpr + , justIssues ++ nothingIssues + ) + + TupleCases (first :: tupleCases) maybeDefaultValue -> + let + ( tupleCasesValues, valuesIssues ) = + createTupleMatchingValues expr mapValue ctx + + ( casesPairs, tupleissues ) = + List.map (\tupleCase -> createCaseCodeForTuplePattern tupleCase tupleCasesValues mapValue ctx) tupleCases + |> List.unzip + + ( mappedDefaultMaybe, defaultMaybeIssues ) = + mapMaybeValue maybeDefaultValue ctx mapValue + + ( firstCase, firstCaseIssues ) = + createCaseCodeForTuplePattern first tupleCasesValues mapValue ctx + in + ( createChainOfWhenWithOptionalOtherwise firstCase casesPairs mappedDefaultMaybe + , defaultMaybeIssues ++ List.concat valuesIssues ++ firstCaseIssues ++ List.concat tupleissues + ) + + _ -> + ( Scala.Variable "NOT_CONVERTED", [ "`Case/of` expression not generated" ] ) + + +mapMaybeValue : Maybe TypedValue -> ValueMappingContext -> Constants.MapValueType -> ( Maybe Scala.Value, List GenerationIssue ) +mapMaybeValue maybeValue ctx mapValue = + let + mappedDefaultMaybeResult = + maybeValue + |> Maybe.map (\defaultValue -> mapValue defaultValue ctx) + + mappedDefaultMaybe = + mappedDefaultMaybeResult + |> Maybe.map Tuple.first + + defaultMaybeIssues = + mappedDefaultMaybeResult + |> Maybe.map Tuple.second + |> Maybe.withDefault [] + in + ( mappedDefaultMaybe, defaultMaybeIssues ) + + +createCaseCodeForTuplePattern : + ( List NestedPatternResult, Value () (Type ()) ) + -> List Scala.Value + -> Constants.MapValueType + -> ValueMappingContext + -> ( ( Scala.Value, Scala.Value ), List GenerationIssue ) +createCaseCodeForTuplePattern ( tuplePats, value ) positionValues mapValue ctx = + let + tuplesForConversion = + List.map2 (\x y -> ( x, y )) tuplePats positionValues + + mappingsContextWithReplacements = + tuplesForConversion + |> List.foldl (\( NestedPatternResult funcs, val ) currCtx -> funcs.contextManipulation val currCtx) ctx + + condition = + tuplesForConversion + |> List.foldr + (\( NestedPatternResult funcs, val ) currentCondition -> + connectWithAnd (funcs.conditionGenerator val) currentCondition + ) + (applySnowparkFunc "lit" [ Scala.Literal (Scala.BooleanLit True) ]) + + ( mappedSuccessValue, successValueIssues ) = + mapValue value mappingsContextWithReplacements + in + ( ( condition, mappedSuccessValue ), successValueIssues ) + + +createTupleMatchingValues : Value () (Type ()) -> Constants.MapValueType -> ValueMappingContext -> ( List Scala.Value, List (List GenerationIssue) ) +createTupleMatchingValues expr mapValue ctx = + case expr of + Value.Tuple _ elements -> + elements + |> List.map (\e -> mapValue e ctx) + |> List.unzip + + _ -> + let + ( convertedTuple, tupleIssues ) = + mapValue expr ctx + in + List.range 0 10 + |> List.map (\i -> ( Scala.Apply convertedTuple [ Scala.ArgValue Nothing (Scala.Literal (Scala.IntegerLit i)) ], tupleIssues )) + |> List.unzip + + +generateBindingVariableExpr : String -> Scala.Value -> Scala.Value +generateBindingVariableExpr name expr = + Scala.Apply expr [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit name)) ] + + +addBindingReplacementsToContext : ValueMappingContext -> List NestedPatternResult -> Scala.Value -> ValueMappingContext +addBindingReplacementsToContext ctxt nestedPatternsInfo referenceExpr = + let + newContext = + nestedPatternsInfo + |> List.indexedMap (\i nestedPatternInfo -> ( nestedPatternInfo, generateBindingVariableExpr (getCustomTypeParameterFieldAccess i) referenceExpr )) + |> List.foldl (\( NestedPatternResult nestedPatternInfo, expr ) newCtxt -> nestedPatternInfo.contextManipulation expr newCtxt) ctxt + in + newContext + + +generateNestedPatternsCondition : List NestedPatternResult -> Scala.Value -> Scala.Value -> Scala.Value +generateNestedPatternsCondition nestedPatternsInfo referenceExpr tagCondition = + nestedPatternsInfo + |> List.indexedMap (\i nestedPatternInfo -> ( nestedPatternInfo, generateBindingVariableExpr (getCustomTypeParameterFieldAccess i) referenceExpr )) + |> List.foldl + (\( NestedPatternResult nestedPatternInfo, expr ) currentExpr -> + connectWithAnd currentExpr (nestedPatternInfo.conditionGenerator expr) + ) + tagCondition + + +type PatternMatchScenario ta + = LiteralsWithDefault (List ( Literal, TypedValue )) TypedValue + | UnionTypesWithoutParams (List ( Scala.Value, TypedValue )) (Maybe TypedValue) + | UnionTypesWithParams (List ( Name.Name, List NestedPatternResult, TypedValue )) (Maybe TypedValue) + | MaybeCase ( Maybe Name.Name, TypedValue ) TypedValue + | TupleCases (List ( List NestedPatternResult, TypedValue )) (Maybe TypedValue) + | Unsupported + + +checkForLiteralCase : ( Pattern (Type ()), TypedValue ) -> Maybe ( Literal, TypedValue ) +checkForLiteralCase ( pattern, caseValue ) = + case pattern of + LiteralPattern _ literal -> + Just ( literal, caseValue ) + + _ -> + Nothing + + +checkLiteralsWithDefault : List ( Pattern (Type ()), TypedValue ) -> Maybe ( List ( Literal, TypedValue ), TypedValue ) +checkLiteralsWithDefault cases = + case List.reverse cases of + ( WildcardPattern _, wildCardResult ) :: restReversed -> + collectMaybeList checkForLiteralCase restReversed |> Maybe.map (\p -> ( List.reverse p, wildCardResult )) + + _ -> + Nothing + + +checkForUnionOfWithNoParams : ( Pattern (Type ()), TypedValue ) -> Maybe ( Scala.Value, TypedValue ) +checkForUnionOfWithNoParams ( pattern, caseValue ) = + case pattern of + ConstructorPattern (Type.Reference _ typeName _) name [] -> + Just ( scalaReferenceToUnionTypeCase typeName name, caseValue ) + + _ -> + Nothing + + +checkConstructorForUnionOfWithParams : ValueMappingContext -> ( Pattern (Type ()), TypedValue ) -> Maybe ( Name.Name, List NestedPatternResult, TypedValue ) +checkConstructorForUnionOfWithParams ctx ( pattern, caseValue ) = + case pattern of + ConstructorPattern _ name patternArgs -> + collectMaybeList (checkNestedItemPattern ctx) patternArgs + |> Maybe.map (\patInfo -> ( FQName.getLocalName name, patInfo, caseValue )) + + _ -> + Nothing + + +checkUnionWithNoParamsWithDefault : TypedValue -> List ( Pattern (Type ()), TypedValue ) -> ValueMappingContext -> Maybe (PatternMatchScenario ta) +checkUnionWithNoParamsWithDefault expr cases ctx = + if isUnionTypeRefWithoutParams (Value.valueAttribute expr) ctx.typesContextInfo then + case List.reverse cases of + ( WildcardPattern _, wildCardResult ) :: restReversed -> + collectMaybeList checkForUnionOfWithNoParams restReversed + |> Maybe.map List.reverse + |> Maybe.map (\p -> UnionTypesWithoutParams p (Just wildCardResult)) + + (( ConstructorPattern _ _ [], _ ) :: _) as constructorCases -> + collectMaybeList checkForUnionOfWithNoParams constructorCases + |> Maybe.map List.reverse + |> Maybe.map (\p -> UnionTypesWithoutParams p Nothing) + + _ -> + Nothing + + else + Nothing + + +checkUnionWithParams : TypedValue -> List ( Pattern (Type ()), TypedValue ) -> ValueMappingContext -> Maybe (PatternMatchScenario ta) +checkUnionWithParams expr cases ctx = + if isUnionTypeRefWithParams (Value.valueAttribute expr) ctx.typesContextInfo then + case List.reverse cases of + ( WildcardPattern _, wildCardResult ) :: restReversed -> + collectMaybeList (checkConstructorForUnionOfWithParams ctx) restReversed + |> Maybe.map List.reverse + |> Maybe.map (\parts -> UnionTypesWithParams parts (Just wildCardResult)) + + (( ConstructorPattern _ _ _, _ ) :: _) as constructorCases -> + collectMaybeList (checkConstructorForUnionOfWithParams ctx) constructorCases + |> Maybe.map List.reverse + |> Maybe.map (\parts -> UnionTypesWithParams parts Nothing) + + _ -> + Nothing + + else + Nothing + + +checkMaybePattern : TypedValue -> List ( Pattern (Type ()), TypedValue ) -> ValueMappingContext -> Maybe (PatternMatchScenario ta) +checkMaybePattern expr cases ctx = + case Value.valueAttribute expr of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) _ -> + case cases of + [ ( ConstructorPattern _ _ [ AsPattern _ (WildcardPattern _) varName ], justExpr ), ( WildcardPattern _, wildCardResult ) ] -> + Just <| MaybeCase ( Just varName, justExpr ) wildCardResult + + [ ( ConstructorPattern _ _ [], nothingExpr ), ( WildcardPattern _, wildCardResult ) ] -> + Just <| MaybeCase ( Nothing, wildCardResult ) nothingExpr + + [ ( ConstructorPattern _ _ [ AsPattern _ (WildcardPattern _) varName ], justExpr ), ( ConstructorPattern _ _ [], nothingExpr ) ] -> + Just <| MaybeCase ( Just varName, justExpr ) nothingExpr + + [ ( ConstructorPattern _ _ [], nothingExpr ), ( ConstructorPattern _ _ [ AsPattern _ (WildcardPattern _) varName ], justExpr ) ] -> + Just <| MaybeCase ( Just varName, justExpr ) nothingExpr + + _ -> + Nothing + + _ -> + Nothing + + +checkForTuplePatternCase : ValueMappingContext -> ( Pattern (Type ()), TypedValue ) -> Maybe ( List NestedPatternResult, TypedValue ) +checkForTuplePatternCase ctx ( pattern, caseValue ) = + case pattern of + TuplePattern _ options -> + (options + |> collectMaybeList (checkNestedItemPattern ctx) + ) + |> Maybe.map (\lst -> ( lst, caseValue )) + + _ -> + Nothing + + +type NestedPatternResult + = NestedPatternResult + { conditionGenerator : Scala.Value -> Scala.Value + , contextManipulation : Scala.Value -> ValueMappingContext -> ValueMappingContext + } + + +checkNestedItemPattern : ValueMappingContext -> Pattern (Type ()) -> Maybe NestedPatternResult +checkNestedItemPattern ctx pattern = + case pattern of + WildcardPattern _ -> + Just <| + NestedPatternResult + { conditionGenerator = \_ -> applySnowparkFunc "lit" [ Scala.Literal (Scala.BooleanLit True) ] + , contextManipulation = \_ innerCtx -> innerCtx + } + + AsPattern _ (WildcardPattern _) name -> + Just <| + NestedPatternResult + { conditionGenerator = \_ -> applySnowparkFunc "lit" [ Scala.Literal (Scala.BooleanLit True) ] + , contextManipulation = addReplacementForIdentifier name + } + + Value.ConstructorPattern _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "just" ] ) [ innerPattern ] -> + checkNestedItemPattern ctx innerPattern + |> Maybe.map + (\(NestedPatternResult patObject) -> + NestedPatternResult + { conditionGenerator = \refr -> connectWithAnd (Scala.Select refr "is_not_null") (patObject.conditionGenerator refr) + , contextManipulation = patObject.contextManipulation + } + ) + + Value.ConstructorPattern ((Type.Reference _ typeName _) as tpe) fullConstructorName [] -> + if isUnionTypeRefWithoutParams tpe ctx.typesContextInfo then + let + unionCaseReference = + scalaReferenceToUnionTypeCase typeName fullConstructorName + in + Just <| + NestedPatternResult + { conditionGenerator = \e -> Scala.BinOp e "===" unionCaseReference + , contextManipulation = \_ innerCtx -> innerCtx + } + + else + Nothing + + Value.LiteralPattern _ literal -> + Just <| + NestedPatternResult + { conditionGenerator = \e -> Scala.BinOp e "===" (mapLiteral () literal) + , contextManipulation = \_ innerCtx -> innerCtx + } + + _ -> + Nothing + + +checkTuplePattern : ValueMappingContext -> List ( Pattern (Type ()), TypedValue ) -> Maybe (PatternMatchScenario ta) +checkTuplePattern ctx cases = + case List.reverse cases of + ( WildcardPattern _, wildCardResult ) :: restReversed -> + collectMaybeList (checkForTuplePatternCase ctx) restReversed + |> Maybe.map List.reverse + |> Maybe.map (\casesToProcess -> TupleCases casesToProcess (Just wildCardResult)) + + (( TuplePattern _ _, _ ) :: _) as constructorCases -> + collectMaybeList (checkForTuplePatternCase ctx) constructorCases + |> Maybe.map List.reverse + |> Maybe.map (\casesToProcess -> TupleCases casesToProcess Nothing) + + _ -> + Nothing + + +classifyScenario : TypedValue -> List ( Pattern (Type ()), TypedValue ) -> ValueMappingContext -> PatternMatchScenario ta +classifyScenario value cases ctx = + Maybe.withDefault + Unsupported + (tryAlternatives + [ \_ -> + checkLiteralsWithDefault cases + |> Maybe.map (\( literalCases, defaultResult ) -> LiteralsWithDefault literalCases defaultResult) + , \_ -> checkUnionWithNoParamsWithDefault value cases ctx + , \_ -> checkUnionWithParams value cases ctx + , \_ -> checkMaybePattern value cases ctx + , \_ -> checkTuplePattern ctx cases + ] + ) + + +connectWithAnd : Scala.Value -> Scala.Value -> Scala.Value +connectWithAnd left right = + case ( left, right ) of + ( Scala.Apply (Scala.Ref _ "lit") [ Scala.ArgValue Nothing (Scala.Literal (Scala.BooleanLit True)) ], _ ) -> + right + + ( _, Scala.Apply (Scala.Ref _ "lit") [ Scala.ArgValue Nothing (Scala.Literal (Scala.BooleanLit True)) ] ) -> + left + + _ -> + Scala.BinOp left "&&" right diff --git a/src/Morphir/Snowpark/RecordWrapperGenerator.elm b/src/Morphir/Snowpark/RecordWrapperGenerator.elm new file mode 100644 index 000000000..865acb6b8 --- /dev/null +++ b/src/Morphir/Snowpark/RecordWrapperGenerator.elm @@ -0,0 +1,420 @@ +module Morphir.Snowpark.RecordWrapperGenerator exposing (generateRecordWrappers) + +import Dict exposing (Dict) +import Morphir.IR.AccessControlled exposing (Access(..), AccessControlled) +import Morphir.IR.Documented exposing (Documented) +import Morphir.IR.FQName as FQName +import Morphir.IR.Module exposing (ModuleName) +import Morphir.IR.Name as Name exposing (Name, toTitleCase) +import Morphir.IR.Package as Package +import Morphir.IR.Type as Type exposing (Field) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants exposing (applyForSnowparkTypesType, applySnowparkFunc, typeRefForSnowparkType) +import Morphir.Snowpark.MappingContext as MappingContext + exposing + ( GlobalDefinitionInformation + , MappingContextInfo + , isRecordWithComplexTypes + , isRecordWithSimpleTypes + , isUnionTypeWithoutParams + ) +import Morphir.Snowpark.TypeRefMapping exposing (generateSnowparkTypeExprFromElmType, mapTypeReference) + + +{-| This module contains to create wrappers for record declarations that represent tables. + +For each record a Trait and an Object is generated with `Column` fields for each member. + +For union types without parameters we are going to generate an object definition with accessors for each option. +| + +-} +generateRecordWrappers : + Package.PackageName + -> ModuleName + -> GlobalDefinitionInformation () + -> Dict Name (AccessControlled (Documented (Type.Definition ()))) + -> List (Scala.Documented (Scala.Annotated Scala.TypeDecl)) +generateRecordWrappers packageName moduleName ( ctx, _, _ ) typesInModule = + typesInModule + |> Dict.toList + |> List.concatMap (processTypeDeclaration packageName moduleName ctx) + + +processTypeDeclaration : + Package.PackageName + -> ModuleName + -> MappingContextInfo () + -> ( Name, AccessControlled (Documented (Type.Definition ())) ) + -> List (Scala.Documented (Scala.Annotated Scala.TypeDecl)) +processTypeDeclaration packageName moduleName ctx ( name, typeDeclAc ) = + -- For the moment we are going generating wrappers for record types + case typeDeclAc.value.value of + Type.TypeAliasDefinition _ (Type.Record _ members) -> + let + fullTypeName = + FQName.fQName packageName moduleName name + in + processRecordDeclaration + name + typeDeclAc.value.doc + members + (isRecordWithSimpleTypes fullTypeName ctx) + (isRecordWithComplexTypes fullTypeName ctx) + ctx + + Type.CustomTypeDefinition _ constructorsAccess -> + processUnionTypeDeclaration + name + constructorsAccess.value + (isUnionTypeWithoutParams (FQName.fQName packageName moduleName name) ctx) + + _ -> + [] + + +processUnionTypeDeclaration : Name -> Type.Constructors () -> Bool -> List (Scala.Documented (Scala.Annotated Scala.TypeDecl)) +processUnionTypeDeclaration name constructors noParams = + if noParams then + [ objectForUnionWithNoParamsValues name constructors + ] + + else + [] + + +processRecordDeclaration : + Name + -> String + -> List (Field ()) + -> Bool + -> Bool + -> MappingContextInfo () + -> List (Scala.Documented (Scala.Annotated Scala.TypeDecl)) +processRecordDeclaration name doc fields recordWithSimpleTypes recordWithComplexTypes ctx = + if recordWithSimpleTypes then + [ traitForRecordWrapper name doc fields + , objectForRecordWrapper name fields ctx + , classForRecordWrapper name fields + ] + + else if recordWithComplexTypes then + [ caseClassForComplexRecord name doc fields ctx ] + + else + [] + + +traitForRecordWrapper : Name -> String -> List (Field a) -> Scala.Documented (Scala.Annotated Scala.TypeDecl) +traitForRecordWrapper name doc fields = + let + members = + fields |> List.map generateTraitMember + in + Scala.Documented (Just doc) + (Scala.Annotated [] + (Scala.Trait + { modifiers = + [] + , name = + name |> toTitleCase + , typeArgs = + [] + , members = + members + , extends = + [] + } + ) + ) + + +generateTraitMember : Field a -> Scala.Annotated Scala.MemberDecl +generateTraitMember field = + Scala.Annotated + [] + (Scala.FunctionDecl + { modifiers = [] + , name = field.name |> Name.toCamelCase + , typeArgs = [] + , args = [] + , returnType = Just (typeRefForSnowparkType "Column") + , body = Nothing + } + ) + + +processComplexRecordField : MappingContextInfo () -> Field () -> Scala.ArgDecl +processComplexRecordField ctx field = + { modifiers = [] + , tpe = mapTypeReference field.tpe MappingContext.Unknown ctx + , name = Name.toCamelCase field.name + , defaultValue = Nothing + } + + +caseClassForComplexRecord : Name -> String -> List (Field ()) -> MappingContextInfo () -> Scala.Documented (Scala.Annotated Scala.TypeDecl) +caseClassForComplexRecord name doc fields ctx = + let + nameToUse = + name |> toTitleCase + + ctorArgs = + fields |> List.map (processComplexRecordField ctx) + in + Scala.Documented Nothing + (Scala.Annotated [] + (Scala.Class + { modifiers = + [ Scala.Case ] + , name = + nameToUse + , typeArgs = + [] + , ctorArgs = + [ ctorArgs ] + , members = + [] + , extends = + [] + , body = + [] + } + ) + ) + + +classForRecordWrapper : Name -> List (Field a) -> Scala.Documented (Scala.Annotated Scala.TypeDecl) +classForRecordWrapper name fields = + let + traitName = + name |> toTitleCase + + nameToUse = + (name |> toTitleCase) ++ "Wrapper" + + members = + fields |> List.map generateWrapperClassMember + + dataFrameArgDecl = + { modifiers = [] + , tpe = typeRefForSnowparkType "DataFrame" + , name = "df" + , defaultValue = Nothing + } + in + Scala.Documented Nothing + (Scala.Annotated [] + (Scala.Class + { modifiers = + [] + , name = + nameToUse + , typeArgs = + [] + , ctorArgs = + [ [ dataFrameArgDecl ] ] + , members = + members + , extends = + [ Scala.TypeRef [] traitName ] + , body = + [] + } + ) + ) + + +emptyDataFrameField : Scala.Annotated Scala.MemberDecl +emptyDataFrameField = + Scala.Annotated + [] + (Scala.ValueDecl + { modifiers = [] + , pattern = Scala.NamedMatch "emptyDataFrameCache" + , valueType = + Just + (Scala.TypeApply + (Scala.TypeRef [ "scala", "collection", "mutable" ] "HashMap") + [ Scala.TypeVar "Boolean", typeRefForSnowparkType "DataFrame" ] + ) + , value = + Scala.New [ "scala", "collection", "mutable" ] "HashMap" [] + } + ) + + +emptyDataFrameMethod : Scala.Annotated Scala.MemberDecl +emptyDataFrameMethod = + let + createDataFrameMethod = + Scala.Select (Scala.Variable "session") "createDataFrame" + + emptySeq = + Scala.Apply (Scala.Variable "Seq") [] + + createDataFrameArgs = + [ Scala.ArgValue Nothing emptySeq, Scala.ArgValue Nothing (Scala.Variable "schema") ] + + arg = + { modifiers = [] + , tpe = typeRefForSnowparkType "Session" + , name = "session" + , defaultValue = Nothing + } + + getOrElseUpdateCall = + Scala.Apply (Scala.Ref [ "emptyDataFrameCache" ] "getOrElseUpdate") + [ Scala.ArgValue Nothing (Scala.Literal (Scala.BooleanLit True)) + , Scala.ArgValue Nothing (Scala.Apply createDataFrameMethod createDataFrameArgs) + ] + in + Scala.Annotated + [] + (Scala.FunctionDecl + { modifiers = [] + , name = "createEmptyDataFrame" + , typeArgs = [] + , args = [ [ arg ] ] + , returnType = Just <| typeRefForSnowparkType "DataFrame" + , body = Just getOrElseUpdateCall + } + ) + + +objectForRecordWrapper : Name -> List (Field ()) -> MappingContextInfo () -> Scala.Documented (Scala.Annotated Scala.TypeDecl) +objectForRecordWrapper name fields ctx = + let + nameToUse = + name |> toTitleCase + + members = + fields |> List.map generateObjectMember + + schema = + generateSchemaDefinition fields ctx + in + Scala.Documented Nothing + (Scala.Annotated [] + (Scala.Object + { modifiers = + [] + , name = + nameToUse + , members = + members ++ [ schema, emptyDataFrameMethod, emptyDataFrameField ] + , extends = + [ Scala.TypeRef [] nameToUse ] + , body = + Nothing + } + ) + ) + + +generateSchemaDefinition : List (Field ()) -> MappingContextInfo () -> Scala.Annotated Scala.MemberDecl +generateSchemaDefinition fields ctx = + let + scalaStringOfName : Name -> Scala.Value + scalaStringOfName name = + Scala.Literal (Scala.StringLit (Name.toTitleCase name)) + + structField = + applyForSnowparkTypesType "StructField" + + fieldTypeArgs : Type.Type () -> List Scala.Value + fieldTypeArgs tpe = + let + ( tpeExpr, isNullable ) = + generateSnowparkTypeExprFromElmType tpe ctx + in + [ tpeExpr, Scala.Literal <| Scala.BooleanLit isNullable ] + + fieldDefinitions = + fields + |> List.map (\field -> structField (scalaStringOfName field.name :: fieldTypeArgs field.tpe)) + in + Scala.Annotated + [] + (Scala.ValueDecl + { modifiers = [] + , pattern = Scala.NamedMatch "schema" + , valueType = Nothing + , value = applyForSnowparkTypesType "StructType" fieldDefinitions + } + ) + + +generateObjectMember : Field a -> Scala.Annotated Scala.MemberDecl +generateObjectMember field = + Scala.Annotated + [] + (Scala.FunctionDecl + { modifiers = [] + , name = field.name |> Name.toCamelCase + , typeArgs = [] + , args = [] + , returnType = Just (typeRefForSnowparkType "Column") + , body = Just (applySnowparkFunc "col" [ Scala.Literal (Scala.StringLit (field.name |> Name.toCamelCase)) ]) + } + ) + + +generateWrapperClassMember : Field a -> Scala.Annotated Scala.MemberDecl +generateWrapperClassMember field = + Scala.Annotated + [] + (Scala.FunctionDecl + { modifiers = [] + , name = field.name |> Name.toCamelCase + , typeArgs = [] + , args = [] + , returnType = Just (typeRefForSnowparkType "Column") + , body = Just (Scala.Apply (Scala.Variable "df") [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit (field.name |> Name.toCamelCase))) ]) + } + ) + + +generateUnionTypeNameMember : String -> Scala.Annotated Scala.MemberDecl +generateUnionTypeNameMember optionName = + Scala.Annotated + [] + (Scala.FunctionDecl + { modifiers = [] + , name = optionName + , typeArgs = [] + , args = [] + , returnType = Just (typeRefForSnowparkType "Column") + , body = Just (applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit optionName) ]) + } + ) + + +objectForUnionWithNoParamsValues : Name -> Type.Constructors ta -> Scala.Documented (Scala.Annotated Scala.TypeDecl) +objectForUnionWithNoParamsValues name constructors = + let + nameToUse = + name |> toTitleCase + + members = + constructors + |> Dict.toList + |> List.map (\( constructorName, _ ) -> generateUnionTypeNameMember (Name.toTitleCase constructorName)) + in + Scala.Documented + Nothing + (Scala.Annotated [] + (Scala.Object + { modifiers = + [] + , name = + nameToUse + , members = + members + , extends = + [] + , body = + Nothing + } + ) + ) diff --git a/src/Morphir/Snowpark/ReferenceUtils.elm b/src/Morphir/Snowpark/ReferenceUtils.elm new file mode 100644 index 000000000..6aeefb022 --- /dev/null +++ b/src/Morphir/Snowpark/ReferenceUtils.elm @@ -0,0 +1,195 @@ +module Morphir.Snowpark.ReferenceUtils exposing + ( curryCall + , errorValueAndIssue + , getCustomTypeParameterFieldAccess + , getExpressionForColumnsObject + , getFunctionInputTypes + , getInnerMaybeType + , getListTypeParameter + , getSourceTargetTypeIfFunctionType + , isTypeReferenceToSimpleTypesRecord + , isValueReferenceToSimpleTypesRecord + , mapLiteral + , mapLiteralToPlainLiteral + , scalaPathToModule + , scalaReferenceToUnionTypeCase + ) + +import Maybe.Extra +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal exposing (Literal(..)) +import Morphir.IR.Name as Name +import Morphir.IR.Type as IrType +import Morphir.IR.Value as Value exposing (TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants as Constants +import Morphir.Snowpark.GenerationReport exposing (GenerationIssue) +import Morphir.Snowpark.MappingContext exposing (MappingContextInfo, ValueMappingContext, getLocalVariableIfDataFrameReference, isRecordWithSimpleTypes) + + +processScalaPackageName : Name.Name -> String +processScalaPackageName name = + (Name.toCamelCase >> String.toLower) name + + +scalaPathToModule : FQName.FQName -> Scala.Path +scalaPathToModule name = + let + packagePath = + FQName.getPackagePath name + |> List.map processScalaPackageName + + modulePath = + case FQName.getModulePath name |> List.reverse of + last :: restInverted -> + (Name.toTitleCase last :: List.map processScalaPackageName restInverted) |> List.reverse + + _ -> + [] + in + packagePath ++ modulePath + + +isValueReferenceToSimpleTypesRecord : Value ta (IrType.Type a) -> MappingContextInfo () -> Maybe ( Scala.Path, Name.Name ) +isValueReferenceToSimpleTypesRecord expression ctx = + isTypeReferenceToSimpleTypesRecord (Value.valueAttribute expression) ctx + + +isTypeReferenceToSimpleTypesRecord : IrType.Type a -> MappingContextInfo () -> Maybe ( Scala.Path, Name.Name ) +isTypeReferenceToSimpleTypesRecord typeReference ctx = + case typeReference of + IrType.Reference _ typeName _ -> + if isRecordWithSimpleTypes typeName ctx then + Just ( scalaPathToModule typeName, FQName.getLocalName typeName ) + + else + Nothing + + _ -> + Nothing + + +mapLiteralToPlainLiteral : ta -> Literal -> Scala.Value +mapLiteralToPlainLiteral _ literal = + case literal of + CharLiteral val -> + Scala.Literal (Scala.CharacterLit val) + + StringLiteral val -> + Scala.Literal (Scala.StringLit val) + + BoolLiteral val -> + Scala.Literal (Scala.BooleanLit val) + + WholeNumberLiteral val -> + Scala.Literal (Scala.IntegerLit val) + + FloatLiteral val -> + Scala.Literal (Scala.FloatLit val) + + _ -> + Debug.todo "The type '_' is not implemented" + + +mapLiteral : ta -> Literal -> Scala.Value +mapLiteral t literal = + Constants.applySnowparkFunc "lit" [ mapLiteralToPlainLiteral t literal ] + + +scalaReferenceToUnionTypeCase : FQName.FQName -> FQName.FQName -> Scala.Value +scalaReferenceToUnionTypeCase typeName constructorName = + let + nsName = + scalaPathToModule constructorName + + containerObjectName = + FQName.getLocalName typeName |> Name.toTitleCase + + containerObjectFieldName = + FQName.getLocalName constructorName |> Name.toTitleCase + in + Scala.Ref (nsName ++ [ containerObjectName ]) containerObjectFieldName + + +getCustomTypeParameterFieldAccess : Int -> String +getCustomTypeParameterFieldAccess paramIndex = + "field" ++ String.fromInt paramIndex + + +getListTypeParameter : IrType.Type () -> Maybe (IrType.Type ()) +getListTypeParameter tpe = + case tpe of + IrType.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] ) [ innertype ] -> + Just innertype + + _ -> + Nothing + + +getFunctionInputTypes : IrType.Type () -> Maybe (List (IrType.Type ())) +getFunctionInputTypes tpe = + case tpe of + IrType.Function _ fromType toType -> + let + toTypes = + getFunctionInputTypes toType + |> Maybe.withDefault [] + in + Just (fromType :: toTypes) + + _ -> + Nothing + + +errorValueAndIssue : GenerationIssue -> ( Scala.Value, List GenerationIssue ) +errorValueAndIssue issue = + ( Scala.Throw (Scala.New [] "Exception" [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit issue)) ]), [ issue ] ) + + +curryCall : ( TypedValue, List TypedValue ) -> TypedValue +curryCall ( func, args ) = + let + resolveOneArgumentOfType tpe = + case tpe of + IrType.Function _ _ returnType -> + returnType + + _ -> + tpe + in + args + |> List.foldl (\arg current -> Value.Apply (resolveOneArgumentOfType (Value.valueAttribute current)) current arg) func + + +getSourceTargetTypeIfFunctionType : IrType.Type a -> Maybe ( IrType.Type a, IrType.Type a ) +getSourceTargetTypeIfFunctionType tpe = + case tpe of + IrType.Function _ fromType toType -> + Just ( fromType, toType ) + + _ -> + Nothing + + +getExpressionForColumnsObject : IrType.Type () -> ValueMappingContext -> Maybe Scala.Value +getExpressionForColumnsObject tpe ctx = + let + fullNameExpr = + isTypeReferenceToSimpleTypesRecord tpe ctx.typesContextInfo + |> Maybe.map (\( path, name ) -> Scala.Ref path (Name.toTitleCase name)) + + localVariableExpr = + getLocalVariableIfDataFrameReference tpe ctx + |> Maybe.map (\name -> Scala.Variable name) + in + Maybe.Extra.orElse fullNameExpr localVariableExpr + + +getInnerMaybeType : IrType.Type () -> Maybe (IrType.Type ()) +getInnerMaybeType tpe = + case tpe of + IrType.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ typeArg ] -> + Just typeArg + + _ -> + Nothing diff --git a/src/Morphir/Snowpark/TypeRefMapping.elm b/src/Morphir/Snowpark/TypeRefMapping.elm new file mode 100644 index 000000000..8414e9211 --- /dev/null +++ b/src/Morphir/Snowpark/TypeRefMapping.elm @@ -0,0 +1,369 @@ +module Morphir.Snowpark.TypeRefMapping exposing + ( generateCastIfPossible + , generateRecordTypeWrapperExpression + , generateSnowparkTypeExprFromElmType + , mapFunctionReturnType + , mapTypeReference + ) + +import Morphir.IR.FQName as FQName +import Morphir.IR.Name as Name +import Morphir.IR.Type as Type exposing (Type(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants + exposing + ( applyForSnowparkTypesType + , applyForSnowparkTypesTypeExpr + , applySnowparkFunc + , typeRefForSnowparkType + ) +import Morphir.Snowpark.MappingContext as MappingContextMod + exposing + ( FunctionClassification + , MappingContextInfo + , ValueMappingContext + , getLocalVariableIfDataFrameReference + , isAliasedBasicType + , isBasicType + , isCandidateForDataFrame + , isDataFrameFriendlyType + , isTypeAlias + , isTypeRefToRecordWithComplexTypes + , isUnionTypeWithParams + , isUnionTypeWithoutParams + , resolveTypeAlias + ) +import Morphir.Snowpark.ReferenceUtils exposing (isTypeReferenceToSimpleTypesRecord, scalaPathToModule) +import Morphir.Snowpark.Utils exposing (tryAlternatives) + + +checkDataFrameCase : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkDataFrameCase typeReference ctx = + if isCandidateForDataFrame typeReference ctx then + Just <| typeRefForSnowparkType "DataFrame" + + else + Nothing + + +checkComplexRecordCase : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkComplexRecordCase typeReference ctx = + if isTypeRefToRecordWithComplexTypes typeReference ctx then + case typeReference of + Type.Reference _ fullName [] -> + Just <| Scala.TypeRef (scalaPathToModule fullName) (fullName |> FQName.getLocalName |> Name.toTitleCase) + + _ -> + Nothing + + else + Nothing + + +checkDataFrameCaseToArray : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkDataFrameCaseToArray typeReference ctx = + if isCandidateForDataFrame typeReference ctx then + Just <| typeRefForSnowparkType "Column" + + else + Nothing + + +checkForFunctionTypeCase : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkForFunctionTypeCase typeReference ctx = + case typeReference of + Type.Function _ fromType toType -> + let + convertedFrom = + mapTypeReferenceForDataFrameOperations fromType ctx + + convertedTo = + mapTypeReferenceForDataFrameOperations toType ctx + in + Just <| Scala.FunctionType convertedFrom convertedTo + + _ -> + Nothing + + +checkForColumnCase : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkForColumnCase typeReference ctx = + if + isBasicType typeReference + || isAliasedBasicType typeReference ctx + || isDataFrameFriendlyType typeReference ctx + || isTypeVariable typeReference + || isMaybeWithGenericType typeReference + then + Just <| typeRefForSnowparkType "Column" + + else + Nothing + + +checkForRecordToColumnCase : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkForRecordToColumnCase typeReference ctx = + isTypeReferenceToSimpleTypesRecord typeReference ctx + |> Maybe.map (\_ -> typeRefForSnowparkType "Column") + + +checkForBasicTypeToScala : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkForBasicTypeToScala tpe ctx = + case tpe of + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) _ -> + Just <| Scala.TypeVar "Int" + + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) _ -> + Just <| Scala.TypeVar "Float" + + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "double" ] ) _ -> + Just <| Scala.TypeVar "Double" + + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "bool" ] ) _ -> + Just <| Scala.TypeVar "Boolean" + + Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) _ -> + Just <| Scala.TypeVar "String" + + Reference _ fullName [] -> + resolveTypeAlias fullName ctx + |> Maybe.map (\resolved -> checkForBasicTypeToScala resolved ctx) + |> Maybe.withDefault Nothing + + _ -> + Nothing + + +checkDefaultCase : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkDefaultCase typeReference ctx = + let + nameInfo = + isTypeReferenceToSimpleTypesRecord typeReference ctx + + typeNameInfo = + Maybe.map + (\( typePath, simpleTypeName ) -> Just (Scala.TypeRef typePath (simpleTypeName |> Name.toTitleCase))) + nameInfo + in + typeNameInfo |> Maybe.withDefault Nothing + + +mapFunctionReturnType : Type () -> FunctionClassification -> MappingContextInfo () -> Scala.Type +mapFunctionReturnType typeReference currentFunctionClassification ctx = + case currentFunctionClassification of + MappingContextMod.FromDataFramesToValues -> + mapTypeReferenceToBuiltinTypes typeReference ctx + + MappingContextMod.FromComplexToValues -> + mapTypeReferenceToBuiltinTypes typeReference ctx + + _ -> + checkForRecordToColumnCase typeReference ctx + |> Maybe.withDefault (mapTypeReference typeReference currentFunctionClassification ctx) + + +mapTypeReference : Type () -> FunctionClassification -> MappingContextInfo () -> Scala.Type +mapTypeReference typeReference currentFunctionClassification ctx = + case currentFunctionClassification of + MappingContextMod.FromDfValuesToDfValues -> + mapTypeReferenceForColumnOperations typeReference ctx + + MappingContextMod.FromComplexToValues -> + mapToScalaTypes typeReference ctx + + MappingContextMod.FromComplexValuesToDataFrames -> + mapToScalaTypes typeReference ctx + + _ -> + mapTypeReferenceForDataFrameOperations typeReference ctx + + +mapToScalaTypes : Type () -> MappingContextInfo () -> Scala.Type +mapToScalaTypes typeReference ctx = + tryAlternatives + [ \_ -> checkDataFrameCase typeReference ctx + , \_ -> checkForBasicTypeToScala typeReference ctx + , \_ -> checkComplexRecordCase typeReference ctx + , \_ -> checkUnionTypeForPlainScala typeReference ctx + ] + |> Maybe.withDefault (Scala.TypeVar "TypeNotConverted") + + +checkUnionTypeForPlainScala : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkUnionTypeForPlainScala tpe ctx = + case tpe of + Type.Reference _ fullTypeName _ -> + if isUnionTypeWithoutParams fullTypeName ctx then + Just <| Scala.TypeVar "String" + + else + Nothing + + _ -> + Nothing + + +mapTypeReferenceForColumnOperations : Type () -> MappingContextInfo () -> Scala.Type +mapTypeReferenceForColumnOperations typeReference ctx = + tryAlternatives + [ \_ -> checkDataFrameCaseToArray typeReference ctx + , \_ -> checkForColumnCase typeReference ctx + , \_ -> checkDefaultCase typeReference ctx + , \_ -> checkForListOfSimpleTypes typeReference ctx + , \_ -> checkComplexRecordCase typeReference ctx + ] + |> Maybe.withDefault (Scala.TypeVar "TypeNotConverted") + + +mapTypeReferenceForDataFrameOperations : Type () -> MappingContextInfo () -> Scala.Type +mapTypeReferenceForDataFrameOperations typeReference ctx = + tryAlternatives + [ \_ -> checkDataFrameCase typeReference ctx + , \_ -> checkForColumnCase typeReference ctx + , \_ -> checkDefaultCase typeReference ctx + , \_ -> checkForListOfSimpleTypes typeReference ctx + , \_ -> checkComplexRecordCase typeReference ctx + , \_ -> checkForFunctionTypeCase typeReference ctx + ] + |> Maybe.withDefault (Scala.TypeVar "TypeNotConverted") + + +generateRecordTypeWrapperExpression : Type () -> ValueMappingContext -> Maybe Scala.Value +generateRecordTypeWrapperExpression typeReference ctx = + getLocalVariableIfDataFrameReference typeReference ctx + |> Maybe.map Scala.Variable + + +isMaybeWithGenericType : Type () -> Bool +isMaybeWithGenericType tpe = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ _ ] -> + True + + _ -> + False + + +isTypeVariable : Type () -> Bool +isTypeVariable tpe = + case tpe of + Type.Variable _ _ -> + True + + _ -> + False + + +checkForListOfSimpleTypes : Type () -> MappingContextInfo () -> Maybe Scala.Type +checkForListOfSimpleTypes typeReference ctx = + if isListOfSimpleType typeReference ctx then + Just <| Scala.TypeApply (Scala.TypeRef [] "Seq") [ typeRefForSnowparkType "Column" ] + + else + Nothing + + +isListOfSimpleType : Type () -> MappingContextInfo () -> Bool +isListOfSimpleType tpe ctx = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "list" ] ], [ "list" ] ) [ elementType ] -> + isDataFrameFriendlyType elementType ctx + + _ -> + False + + +mapTypeReferenceToBuiltinTypes : Type () -> MappingContextInfo () -> Scala.Type +mapTypeReferenceToBuiltinTypes tpe ctx = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) [] -> + Scala.TypeVar "Double" + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) [] -> + Scala.TypeVar "Int" + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) [] -> + Scala.TypeVar "String" + + Type.Reference _ fullTypeName [] -> + if isTypeAlias fullTypeName ctx then + resolveTypeAlias fullTypeName ctx + |> Maybe.map (\t -> mapTypeReferenceToBuiltinTypes t ctx) + |> Maybe.withDefault (Scala.TypeVar "TypeNotConverted") + + else + Scala.TypeVar "TypeNotConverted" + + _ -> + Scala.TypeVar "TypeNotConverted" + + +generateCastIfPossible : ValueMappingContext -> Type () -> Scala.Value -> Scala.Value +generateCastIfPossible ctx tpe value = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) [] -> + applySnowparkFunc "as_double" [ value ] + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) [] -> + applySnowparkFunc "as_integer" [ value ] + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) [] -> + applySnowparkFunc "as_char" [ value ] + + Type.Reference _ fullName [] -> + if isTypeAlias fullName ctx.typesContextInfo then + resolveTypeAlias fullName ctx.typesContextInfo + |> Maybe.map (\t -> generateCastIfPossible ctx t value) + |> Maybe.withDefault value + + else + value + + _ -> + value + + +generateSnowparkTypeExprFromElmType : Type () -> MappingContextInfo () -> ( Scala.Value, Bool ) +generateSnowparkTypeExprFromElmType tpe ctx = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) [] -> + ( applyForSnowparkTypesTypeExpr "FloatType", False ) + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "double" ] ) [] -> + ( applyForSnowparkTypesTypeExpr "DoubleType", False ) + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) [] -> + ( applyForSnowparkTypesTypeExpr "IntegerType", False ) + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "bool" ] ) [] -> + ( applyForSnowparkTypesTypeExpr "BooleanType", False ) + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) [] -> + ( applyForSnowparkTypesTypeExpr "StringType", False ) + + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ innerType ] -> + let + ( generatedType, _ ) = + generateSnowparkTypeExprFromElmType innerType ctx + in + ( generatedType, True ) + + Type.Reference _ fullTypeName [] -> + if isUnionTypeWithoutParams fullTypeName ctx then + ( applyForSnowparkTypesTypeExpr "StringType", False ) + + else if isUnionTypeWithParams fullTypeName ctx then + ( applyForSnowparkTypesType "MapType" + [ applyForSnowparkTypesTypeExpr "StringType" + , applyForSnowparkTypesTypeExpr "StringType" + ] + , True + ) + + else + resolveTypeAlias fullTypeName ctx + |> Maybe.map (\t -> generateSnowparkTypeExprFromElmType t ctx) + |> Maybe.withDefault ( applyForSnowparkTypesTypeExpr "VariantType", True ) + + _ -> + ( applyForSnowparkTypesTypeExpr "VariantType", True ) diff --git a/src/Morphir/Snowpark/UserDefinedFunctionMapping.elm b/src/Morphir/Snowpark/UserDefinedFunctionMapping.elm new file mode 100644 index 000000000..4ecd802cd --- /dev/null +++ b/src/Morphir/Snowpark/UserDefinedFunctionMapping.elm @@ -0,0 +1,164 @@ +module Morphir.Snowpark.UserDefinedFunctionMapping exposing (tryToConvertUserFunctionCall) + +import Morphir.IR.FQName as FQName +import Morphir.IR.Name as Name +import Morphir.IR.Type exposing (Type) +import Morphir.IR.Value as ValueIR exposing (Pattern(..), TypedValue, Value(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Constants as Constants exposing (ValueGenerationResult, applySnowparkFunc) +import Morphir.Snowpark.MappingContext + exposing + ( FunctionClassification(..) + , ValueMappingContext + , isAliasedBasicType + , isBasicType + , isFunctionReceivingDataFrameExpressions + , isLocalFunctionName + , isLocalVariableDefinition + , isRecordWithSimpleTypes + ) +import Morphir.Snowpark.ReferenceUtils + exposing + ( errorValueAndIssue + , getCustomTypeParameterFieldAccess + , getFunctionInputTypes + , scalaPathToModule + ) + + +tryToConvertUserFunctionCall : ( TypedValue, List TypedValue ) -> Constants.MapValueType -> ValueMappingContext -> ValueGenerationResult +tryToConvertUserFunctionCall ( func, args ) mapValue ctx = + case func of + ValueIR.Reference functionType functionName -> + if isLocalFunctionName functionName ctx then + let + funcReference = + Scala.Ref (scalaPathToModule functionName) + (functionName |> FQName.getLocalName |> Name.toCamelCase) + + ( argsConverted, argsIssues ) = + args + |> List.map (\arg -> mapValue arg ctx) + |> List.unzip + + argsToUse = + checkIfArgumentsNeedsToBeAdapted functionName functionType argsConverted ctx + |> List.map (Scala.ArgValue Nothing) + + issues = + List.concat argsIssues + in + case argsToUse of + [] -> + ( funcReference, issues ) + + first :: rest -> + ( List.foldl (\a c -> Scala.Apply c [ a ]) (Scala.Apply funcReference [ first ]) rest, issues ) + + else + ( Scala.Throw (Scala.New [] "Exception" [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit "Call not generated")) ]) + , [ "Call to function not generated: " ++ FQName.toString functionName ] + ) + + ValueIR.Constructor _ constructorName -> + if isRecordWithSimpleTypes constructorName ctx.typesContextInfo then + let + ( argsToUse, issues ) = + args + |> List.map (\arg -> mapValue arg ctx) + |> List.unzip + in + ( Constants.applySnowparkFunc "array_construct" argsToUse, List.concat issues ) + + else if isLocalFunctionName constructorName ctx && List.length args > 0 then + let + ( mappedArgs, issuesPerArg ) = + args + |> List.map (\arg -> mapValue arg ctx) + |> List.unzip + + argsToUse = + mappedArgs + |> List.indexedMap (\i arg -> ( getCustomTypeParameterFieldAccess i, arg )) + |> List.concatMap (\( field, value ) -> [ Constants.applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit field) ], value ]) + + tagName = + constructorName |> FQName.getLocalName |> Name.toTitleCase + + tag = + [ Constants.applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit "__tag") ] + , Constants.applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit tagName) ] + ] + in + ( Constants.applySnowparkFunc "object_construct" (tag ++ argsToUse), List.concat issuesPerArg ) + + else + errorValueAndIssue ("Constructor call not converted: `" ++ FQName.toString constructorName ++ "`") + + ValueIR.Variable _ funcName -> + if + List.member funcName ctx.parameters + || isLocalVariableDefinition funcName ctx + then + let + ( mappedArgs, issuesPerArg ) = + args + |> List.map (\arg -> mapValue arg ctx) + |> List.unzip + + argsToUse = + mappedArgs + |> List.map (Scala.ArgValue Nothing) + in + case argsToUse of + [] -> + ( Scala.Variable (Name.toCamelCase funcName), [] ) + + first :: rest -> + ( List.foldl + (\a c -> Scala.Apply c [ a ]) + (Scala.Apply (Scala.Variable (Name.toCamelCase funcName)) [ first ]) + rest + , List.concat issuesPerArg + ) + + else + errorValueAndIssue "Call to variable function not generated" + + _ -> + errorValueAndIssue "Call not generated" + + +checkIfArgumentsNeedsToBeAdapted : + FQName.FQName + -> Type () + -> List Scala.Value + -> ValueMappingContext + -> List Scala.Value +checkIfArgumentsNeedsToBeAdapted invokedFunctionName functionType args ctx = + let + inPlainScalaFunction = + ctx.currentFunctionClassification + == FromComplexValuesToDataFrames + || ctx.currentFunctionClassification + == FromComplexToValues + in + if + inPlainScalaFunction + && isFunctionReceivingDataFrameExpressions invokedFunctionName ctx + then + getFunctionInputTypes functionType + |> Maybe.map (\inputTypes -> List.map2 (adaptArgumentToDfExpr ctx) args inputTypes) + |> Maybe.withDefault args + + else + args + + +adaptArgumentToDfExpr : ValueMappingContext -> Scala.Value -> Type () -> Scala.Value +adaptArgumentToDfExpr ctx arg targetArgType = + if isBasicType targetArgType || isAliasedBasicType targetArgType ctx.typesContextInfo then + applySnowparkFunc "lit" [ arg ] + + else + arg diff --git a/src/Morphir/Snowpark/Utils.elm b/src/Morphir/Snowpark/Utils.elm new file mode 100644 index 000000000..061b44414 --- /dev/null +++ b/src/Morphir/Snowpark/Utils.elm @@ -0,0 +1,33 @@ +module Morphir.Snowpark.Utils exposing (collectMaybeList, tryAlternatives) + + +tryAlternatives : List (() -> Maybe a) -> Maybe a +tryAlternatives cases = + case cases of + first :: rest -> + case first () of + (Just _) as result -> + result + + _ -> + tryAlternatives rest + + [] -> + Nothing + + +collectMaybeList : (a -> Maybe b) -> List a -> Maybe (List b) +collectMaybeList action aList = + collectMaybeListAux action aList [] + + +collectMaybeListAux : (a -> Maybe b) -> List a -> List b -> Maybe (List b) +collectMaybeListAux action aList current = + case aList of + first :: rest -> + action first + |> Maybe.map (\newFirst -> collectMaybeListAux action rest (newFirst :: current)) + |> Maybe.withDefault Nothing + + [] -> + Just (List.reverse current) diff --git a/src/Morphir/TestCoverage/Backend.elm b/src/Morphir/TestCoverage/Backend.elm index c29ae2bf6..19526e7c4 100644 --- a/src/Morphir/TestCoverage/Backend.elm +++ b/src/Morphir/TestCoverage/Backend.elm @@ -1,4 +1,4 @@ -module Morphir.TestCoverage.Backend exposing (TestCoverageResult, getBranchCoverage) +module Morphir.TestCoverage.Backend exposing (TestCoverageResult, getBranchCoverage, getValueBranchCoverage) import AssocList as AssocDict import Dict exposing (Dict) @@ -9,6 +9,7 @@ import Morphir.IR.FQName as FQName exposing (FQName) import Morphir.IR.Module as Module exposing (ModuleName) import Morphir.IR.NodeId exposing (..) import Morphir.IR.Package exposing (PackageName) +import Morphir.IR.Value as Value type alias Coverage = @@ -56,13 +57,18 @@ getBranchCoverage ( packageName, moduleName ) ir testSuite moduleDef = accesscontrolledValueDef.value.value in ( ValueID currentFQN [] - , valueTestCases - |> BranchCoverage.assignTestCasesToBranches ir valueDef - |> (\lstOfBranchAndCoveredTestCases -> - { numberOfBranches = lstOfBranchAndCoveredTestCases |> List.length - , numberOfCoveredBranches = calculateNumberOfCoveredBranches lstOfBranchAndCoveredTestCases - } - ) + , getValueBranchCoverage valueDef valueTestCases ir ) ) |> AssocDict.fromList + + +getValueBranchCoverage : Value.Definition ta va -> List TestCase -> Distribution -> Coverage +getValueBranchCoverage valueDef valueTestCases ir = + valueTestCases + |> BranchCoverage.assignTestCasesToBranches ir valueDef + |> (\lstOfBranchAndCoveredTestCases -> + { numberOfBranches = lstOfBranchAndCoveredTestCases |> List.length + , numberOfCoveredBranches = calculateNumberOfCoveredBranches lstOfBranchAndCoveredTestCases + } + ) diff --git a/src/Morphir/Value/Native.elm b/src/Morphir/Value/Native.elm index c90e92abb..8969563ab 100644 --- a/src/Morphir/Value/Native.elm +++ b/src/Morphir/Value/Native.elm @@ -3,7 +3,7 @@ module Morphir.Value.Native exposing , Eval , unaryLazy, unaryStrict, binaryLazy, binaryStrict, boolLiteral, charLiteral, eval0, eval1, eval2, eval3 , floatLiteral, intLiteral, oneOf, stringLiteral, decimalLiteral - , decodeFun1, decodeList, decodeLiteral, decodeMaybe, decodeLocalDate, decodeRaw, decodeTuple2, encodeList, encodeLiteral, encodeMaybe, encodeLocalDate, encodeMaybeResult, encodeRaw, encodeResultList, encodeTuple2 + , decodeFun1, decodeList, decodeLiteral, decodeMaybe, decodeLocalDate, decodeRaw, decodeTuple2, encodeList, encodeLiteral, encodeMaybe, encodeLocalDate, encodeMaybeResult, encodeRaw, encodeResultList, encodeTuple2, decodeDict, decodeFun2, encodeDict , trinaryLazy, trinaryStrict ) @@ -39,7 +39,7 @@ Various utilities to help with implementing native functions. @docs unaryLazy, unaryStrict, binaryLazy, binaryStrict, boolLiteral, charLiteral, eval0, eval1, eval2, eval3 @docs floatLiteral, intLiteral, oneOf, stringLiteral, decimalLiteral -@docs decodeFun1, decodeList, decodeLiteral, decodeMaybe, decodeLocalDate, decodeRaw, decodeTuple2, encodeList, encodeLiteral, encodeMaybe, encodeLocalDate, encodeMaybeResult, encodeRaw, encodeResultList, encodeTuple2 +@docs decodeFun1, decodeList, decodeLiteral, decodeMaybe, decodeLocalDate, decodeRaw, decodeTuple2, encodeList, encodeLiteral, encodeMaybe, encodeLocalDate, encodeMaybeResult, encodeRaw, encodeResultList, encodeTuple2, decodeDict, decodeFun2, encodeDict @docs trinaryLazy, trinaryStrict -} @@ -47,6 +47,7 @@ Various utilities to help with implementing native functions. import Morphir.IR.Literal exposing (Literal(..)) import Morphir.IR.Value as Value exposing (RawValue, Value) import Morphir.SDK.Decimal exposing (Decimal) +import Morphir.SDK.Dict as Dict exposing (Dict) import Morphir.SDK.LocalDate as LocalDate exposing (LocalDate) import Morphir.SDK.ResultList as ListOfResults import Morphir.Value.Error exposing (Error(..)) @@ -242,6 +243,29 @@ decodeList decodeItem eval value = Err error +{-| -} +decodeDict : Decoder k -> Decoder v -> Decoder (Dict k v) +decodeDict decodeKey decodeValue eval value = + case eval value of + Ok (Value.Apply _ (Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "dict" ] ], [ "from", "list" ] )) list) -> + list + |> decodeList (decodeTuple2 ( decodeKey, decodeValue )) eval + |> Result.map Dict.fromList + + Ok _ -> + Err (ExpectedList value) + + Err error -> + Err error + + +{-| -} +encodeDict : Encode k -> Encode v -> Dict k v -> Result Error RawValue +encodeDict encodeKey encodeValue dict = + Dict.toList dict + |> encodeList (encodeTuple2 ( encodeKey, encodeValue )) + + {-| -} encodeTuple2 : ( Encode a, Encode b ) -> ( a, b ) -> Result Error RawValue encodeTuple2 ( encodeA, encodeB ) ( a, b ) = @@ -275,6 +299,24 @@ decodeFun1 encodeA decodeR eval fun = ) +{-| -} +decodeFun2 : Encode a -> Encode b -> Decoder r -> Decoder (a -> b -> Result Error r) +decodeFun2 encodeA encodeB decodeR eval fun = + Ok + (\a b -> + encodeA a + |> Result.andThen + (\arg1 -> + encodeB b + |> Result.andThen + (\arg2 -> + eval (Value.Apply () (Value.Apply () fun arg1) arg2) + |> Result.andThen (decodeR eval) + ) + ) + ) + + {-| -} boolLiteral : Literal -> Result Error Bool boolLiteral lit = diff --git a/src/Morphir/Visual/Components/DecisionTable.elm b/src/Morphir/Visual/Components/DecisionTable.elm index 1042d03ca..a63bc209f 100644 --- a/src/Morphir/Visual/Components/DecisionTable.elm +++ b/src/Morphir/Visual/Components/DecisionTable.elm @@ -22,6 +22,7 @@ import Morphir.Visual.Common exposing (nameToText) import Morphir.Visual.Config exposing (Config, HighlightState(..), VisualState) import Morphir.Visual.EnrichedValue exposing (EnrichedValue) import Morphir.Visual.Theme exposing (mediumPadding) +import Morphir.IR.Name exposing (toHumanWordsTitle) @@ -179,11 +180,11 @@ getCaseFromIndex config head viewValue highlightState rule = let parsedMatches : List (Element msg) parsedMatches = - List.map (getCaseFromIndex config head viewValue highlightState << Just << toTypedPattern) (matches |> Debug.log "matches") + List.map (getCaseFromIndex config head viewValue highlightState << Just << toTypedPattern) matches --enclose in parentheses for nested constructors in - row [ width fill, Background.color result, mediumPadding config.state.theme |> padding ] (List.concat [ [ text "(", text (nameToText (getLocalName fQName)) ], List.intersperse (text ",") parsedMatches, [ text ")" ] ]) + row [ width fill, Background.color result, mediumPadding config.state.theme |> padding ] (List.concat [ [ text "(", text ((toHumanWordsTitle >> String.join " ") (getLocalName fQName)) ], List.intersperse (text ",") parsedMatches, [ text ")" ] ]) Value.AsPattern _ (Value.WildcardPattern _) name -> el [ Background.color result, mediumPadding config.state.theme |> padding ] (text (nameToText name)) diff --git a/src/Morphir/Visual/Components/DrillDownPanel.elm b/src/Morphir/Visual/Components/DrillDownPanel.elm index 76c968a74..b6e4d3f86 100644 --- a/src/Morphir/Visual/Components/DrillDownPanel.elm +++ b/src/Morphir/Visual/Components/DrillDownPanel.elm @@ -58,7 +58,7 @@ drillDownPanel theme config = , blur = 4 , color = rgba 0 0 0 0.2 } - , Background.color (rgba 1 1 1 1) + , Background.color theme.colors.lightest , htmlAttribute (style "filter" "brightness(97%)") , htmlAttribute (style "z-index" (String.fromInt config.zIndex)) ] @@ -74,6 +74,7 @@ drillDownPanel theme config = , Border.rounded 4 , Border.width 2 , Border.color (rgba 0 0 0 0.1) + , Background.color theme.colors.lightest ] [ el [ width (theme |> Theme.largeSpacing |> px) ] (expandIcon theme) , config.closedElement diff --git a/src/Morphir/Visual/Components/FieldList.elm b/src/Morphir/Visual/Components/FieldList.elm index 2ca04022f..e43e7c35d 100644 --- a/src/Morphir/Visual/Components/FieldList.elm +++ b/src/Morphir/Visual/Components/FieldList.elm @@ -1,15 +1,14 @@ module Morphir.Visual.Components.FieldList exposing (..) -import Element exposing (Element, centerY, el, fill, paddingXY, rgb, shrink, spacingXY, table, text, width) -import Element.Background as Background +import Element exposing (Element, centerY, el, fill, padding, shrink, spacingXY, table, text, width) import Element.Border as Border -import Element.Font as Font import Morphir.IR.Name exposing (Name) import Morphir.Visual.Common exposing (nameToText) +import Morphir.Visual.Theme as Theme exposing (Theme) -view : List ( Name, Element msg ) -> Element msg -view fields = +view : Theme -> List ( Name, Element msg ) -> Element msg +view theme fields = table [ width fill , spacingXY 0 5 @@ -20,12 +19,9 @@ view fields = , view = \( fieldName, _ ) -> el - [ width fill - , paddingXY 10 5 + [ width shrink , centerY - , Font.color (rgb 1 1 1) - , Font.bold - , Background.color (rgb 0.2 0.3 0.4) + , padding <| Theme.smallPadding theme , Border.roundEach { topLeft = 6 , bottomLeft = 6 @@ -33,7 +29,7 @@ view fields = , bottomRight = 0 } ] - (text (nameToText fieldName)) + (text <| nameToText fieldName ++ " : ") } , { header = text "" , width = shrink diff --git a/src/Morphir/Visual/Components/InputComponent.elm b/src/Morphir/Visual/Components/InputComponent.elm index e120dd6ea..1e01cd224 100644 --- a/src/Morphir/Visual/Components/InputComponent.elm +++ b/src/Morphir/Visual/Components/InputComponent.elm @@ -1,12 +1,11 @@ -module Morphir.Visual.Components.InputComponent exposing (textInput, searchInput, checkBox, multiLine) +module Morphir.Visual.Components.InputComponent exposing (checkBox, multiLine, searchInput, textInput) -import Element exposing (Element, below, el, moveDown, padding, paddingXY, rgb, text) +import Element exposing (Element, below, el, moveDown, padding, paddingXY, rgb, rgba, text) import Element.Background as Background import Element.Border as Border import Element.Font as Font import Element.Input import Morphir.Visual.Theme as Theme exposing (Theme) -import Element exposing (rgba) type alias TextInputConfig msg = @@ -16,6 +15,7 @@ type alias TextInputConfig msg = , label : Element.Input.Label msg } + type alias MultilineTextInputConfig msg = { onChange : String -> msg , text : String @@ -34,10 +34,18 @@ type alias CheckboxConfig msg = defaultStyles : Theme -> List (Element.Attribute msg) defaultStyles theme = - [ Element.focused [ Border.color theme.colors.primaryHighlight ] - , paddingXY (Theme.smallPadding theme) 3 + [ Element.focused + [ Border.color theme.colors.primaryHighlight + , Border.shadow + { offset = ( 0, 0 ) + , size = 0 + , blur = 3 + , color = theme.colors.primaryHighlight + } + ] + , paddingXY (theme |> Theme.mediumPadding) (theme |> Theme.smallPadding) , Font.size theme.fontSize - , Border.width 2 + , Theme.borderRounded theme ] @@ -60,7 +68,7 @@ errorStyles theme error = ] Nothing -> - [ ] + [] textInput : Theme -> List (Element.Attribute msg) -> TextInputConfig msg -> Maybe String -> Element msg @@ -75,8 +83,9 @@ searchInput theme attributes config = checkBox : Theme -> List (Element.Attribute msg) -> CheckboxConfig msg -> Element msg checkBox theme attributes config = - Element.Input.checkbox ( (Border.color (rgba 0 0 0 0)) :: attributes) { onChange = config.onChange, checked = config.checked, label = config.label, icon = Element.Input.defaultCheckbox } + Element.Input.checkbox (Border.color (rgba 0 0 0 0) :: attributes) { onChange = config.onChange, checked = config.checked, label = config.label, icon = Element.Input.defaultCheckbox } + multiLine : Theme -> List (Element.Attribute msg) -> MultilineTextInputConfig msg -> Maybe String -> Element msg multiLine theme attributes config error = - Element.Input.multiline (defaultStyles theme ++ errorStyles theme error ++ attributes) config \ No newline at end of file + Element.Input.multiline (defaultStyles theme ++ errorStyles theme error ++ attributes) config diff --git a/src/Morphir/Visual/Components/Picklist.elm b/src/Morphir/Visual/Components/Picklist.elm index 06991bd46..eb5c12f61 100644 --- a/src/Morphir/Visual/Components/Picklist.elm +++ b/src/Morphir/Visual/Components/Picklist.elm @@ -1,4 +1,7 @@ -module Morphir.Visual.Components.Picklist exposing (State, init, getSelectedTag, view) +module Morphir.Visual.Components.Picklist exposing + ( State, init, view + , getSelectedValue + ) {-| This module implements a component that allows users to pick an item from a dropdown list. @@ -47,21 +50,49 @@ module Morphir.Visual.Components.Picklist exposing (State, init, getSelectedTag, -- check out the Config type docs for further details { state = model.picklist , onStateChange = PicklistChanged - , selectedTag = model.selectedOption + , selectedvalue = model.selectedOption , onSelectionChange = OptionSelected } -- this is where you specify the selectable values - -- each entry is a tuple where the first element is the "tag" that represents the selection - [ ( Option1, "Option A" ) - , ( Option2, "Option B" ) - ] + -- each entry is a (DropdownElement msg value ) type record + -- with .displayElement field for displaying the value to the user + -- a .value field to store the actual used value + -- and a .tag field for search purposes ] -@docs State, init, getSelectedTag, view +@docs State, init, getSelectedvalue, view -} -import Element exposing (Element, alignRight, behindContent, below, column, el, fill, focused, height, html, htmlAttribute, maximum, minimum, mouseOver, moveDown, none, paddingEach, paddingXY, px, rgb255, rgba, row, shrink, spacing, text, transparent, width) +import Element + exposing + ( Element + , alignRight + , below + , column + , el + , fill + , focused + , height + , html + , inFront + , maximum + , minimum + , moveDown + , none + , paddingEach + , padding + , paddingXY + , pointer + , px + , rgb255 + , rgba + , row + , shrink + , spacing + , text + , width + ) import Element.Background as Background import Element.Border as Border import Element.Events as Events @@ -70,42 +101,48 @@ import Element.Input as Input import FontAwesome as Icon import FontAwesome.Attributes as Icon import FontAwesome.Solid as Icon -import Html.Attributes import Morphir.Visual.Common exposing (colorToSvg) +import Morphir.Visual.Components.InputComponent exposing (searchInput) +import Morphir.Visual.Components.SelectableElement as SelectableElement import Morphir.Visual.Theme as Theme exposing (Theme) import Svg.Attributes {-| Type that contains the internal state of this component. -} -type alias State tag = - { selectedTag : Maybe tag +type alias State value = + { selectedValue : Maybe value , dropDownOpen : Bool + , searchText : Maybe String + , targeted : Bool } {-| Initialize the state of the component. -} -init : Maybe tag -> State tag -init selectedTag = - { selectedTag = selectedTag +init : Maybe value -> State value +init selectedValue = + { selectedValue = selectedValue , dropDownOpen = False + , searchText = Nothing + , targeted = True } -{-| Get the currently selected tag value. +{-| Get the currently selected value value. -} -getSelectedTag : State tag -> Maybe tag -getSelectedTag state = - state.selectedTag +getSelectedValue : State value -> Maybe value +getSelectedValue state = + state.selectedValue -type Msg tag +type Msg value = ToggleDropdown | CloseDropdown + | SearchText String -update : Msg tag -> State tag -> State tag +update : Msg value -> State value -> State value update msg state = case msg of ToggleDropdown -> @@ -114,9 +151,28 @@ update msg state = } CloseDropdown -> - { state - | dropDownOpen = False - } + if not state.targeted then + { state + | dropDownOpen = False + , targeted = False + } + + else + state + + SearchText searchText -> + case searchText of + "" -> + { state + | searchText = Nothing + } + + _ -> + { state + | searchText = Just searchText + , dropDownOpen = True + , selectedValue = Nothing + } {-| Configuration for the Picklist: @@ -127,9 +183,26 @@ update msg state = - Called when the internal state of the component changes. -} -type alias Config msg tag = - { state : State tag - , onStateChange : State tag -> msg +type alias Config msg value = + { state : State value + , onStateChange : State value -> msg + } + + +{-| An element of the OrderedDropdown: + + - _tag_ + - Used for search purposes + - _value_ + - The value of the selected element we'd like to use. + - _displayElement_ + - How the elment should be displayed in the dropdown. + +-} +type alias DropdownElement msg value = + { tag : String + , value : value + , displayElement : Element msg } @@ -141,35 +214,77 @@ type alias Config msg tag = - This is where you should do your wiring of states and event handlers. See the docs on `Config` for more details. - _selectableValues_ - This is where you can specify what will be in the drop-down list. It's a tuple with 2 elements: - - The "tag" value that is returned by the selection change event. + - The "value" value that is returned by the selection change event. - The visual representation. -} -view : Theme -> Config msg tag -> List ( tag, Element msg ) -> Element msg -view theme config selectableValues = +view : Theme -> Config msg value -> List (DropdownElement msg value) -> List (DropdownElement msg value) -> Element msg +view theme config priorityElements generalElements = let + state : State value + state = + config.state + selectedValue : Maybe (Element msg) selectedValue = config.state - |> getSelectedTag + |> getSelectedValue |> Maybe.andThen (\selected -> - selectableValues + (priorityElements ++ generalElements) |> List.filterMap - (\( tag, content ) -> - if tag == selected then - Just content + (\element -> + if element.value == selected then + Just <| + element.displayElement else Nothing ) |> List.head ) - in - el [] - (Input.button + + displaySelectedvalue : Element msg + displaySelectedvalue = + case selectedValue of + Just selected -> + case config.state.searchText of + Just _ -> + Element.none + + Nothing -> + row [ width fill, height fill, Background.color theme.colors.lightest, pointer, paddingXY 2 0, Theme.borderRounded theme ] + [ el [ width fill, height (shrink |> minimum (Theme.scaled 5 theme) |> maximum (Theme.scaled 5 theme)), Element.clipY ] + selected + , el [ alignRight ] + (html (Icon.caretDown |> Icon.styled [ Icon.lg ] |> Icon.view)) + ] + + Nothing -> + Element.none + + displayDropDown : Element msg + displayDropDown = + if config.state.dropDownOpen then + let + onSelectionChange : Maybe value -> msg + onSelectionChange selected = + config.onStateChange (init selected) + in + viewDropdown theme config.state.selectedValue onSelectionChange (priorityElements ++ generalElements) config.state.searchText + |> el + [ Events.onMouseEnter <| config.onStateChange { state | targeted = True } + , Events.onMouseLeave <| config.onStateChange { state | targeted = False } + ] + + else + none + + inputElementAttributes : List (Element.Attribute msg) + inputElementAttributes = [ width (shrink |> minimum (theme.fontSize * 14) |> maximum (theme.fontSize * 20)) , paddingXY (theme |> Theme.mediumPadding) (theme |> Theme.smallPadding) + , height fill , Border.width 1 , theme |> Theme.borderRounded , Border.color (grey 201) @@ -184,84 +299,49 @@ view theme config selectableValues = , color = theme.colors.primaryHighlight } ] - , below - (if config.state.dropDownOpen then - let - onSelectionChange : Maybe tag -> msg - onSelectionChange selectedTag = - let - state : State tag - state = - config.state - in - config.onStateChange { state | selectedTag = selectedTag, dropDownOpen = False } - in - viewDropdown theme config.state.selectedTag onSelectionChange selectableValues - - else - none - ) + , below displayDropDown + , inFront displaySelectedvalue , Events.onLoseFocus (config.onStateChange (update CloseDropdown config.state)) ] - { onPress = - if config.state.dropDownOpen then - Nothing - - else - Just (config.onStateChange (update ToggleDropdown config.state)) - , label = - let - labelContent : Element msg - labelContent = - case selectedValue of - Just selected -> - el [ width fill ] - selected + ++ (if not config.state.dropDownOpen then + [ Events.onClick (config.onStateChange (update ToggleDropdown config.state)) ] - Nothing -> - el - [ width fill - , Font.color (grey 160) - ] - viewUnselected - in - row [ width fill, height fill ] - [ labelContent - , el [ alignRight ] - (html (Icon.caretDown |> Icon.styled [ Icon.lg ] |> Icon.view)) - ] - } - ) + else + [] + ) + in + searchInput + theme + inputElementAttributes + { onChange = \s -> config.onStateChange (update (SearchText s) config.state) + , text = config.state.searchText |> Maybe.withDefault "" + , label = Input.labelHidden "Search for an option" + , placeholder = Just <| Input.placeholder [] viewUnselected + } -viewDropdown : Theme -> Maybe tag -> (Maybe tag -> msg) -> List ( tag, Element msg ) -> Element msg -viewDropdown theme selectedTag onSelectionChange selectableValues = +viewDropdown : Theme -> Maybe value -> (Maybe value -> msg) -> List (DropdownElement msg value) -> Maybe String -> Element msg +viewDropdown theme selectedvalue onSelectionChange selectableValues searchText = let viewListItem : { icon : Element msg, label : Element msg, onClick : msg } -> Element msg viewListItem args = - row - [ height (px (theme.fontSize * 2)) - , width fill - , paddingEach - { top = theme |> Theme.smallPadding - , right = theme |> Theme.mediumPadding - , bottom = theme |> Theme.smallPadding - , left = theme |> Theme.mediumPadding - } - , spacing (theme |> Theme.smallSpacing) - , Font.color (grey 24) - , mouseOver - [ Background.color (grey 243) - ] - , Events.onClick args.onClick - ] - [ el [ width (px 20) ] args.icon - , args.label - ] + SelectableElement.view theme + { onSelect = args.onClick + , isSelected = False + , content = + row + [ width fill + , paddingXY 0 (theme |> Theme.smallPadding) + , Font.color (grey 24) + ] + [ el [ width (px 20) ] args.icon + , args.label + ] + } unselectElem : List (Element msg) unselectElem = - if selectedTag == Nothing then + if selectedvalue == Nothing then [] else @@ -277,19 +357,27 @@ viewDropdown theme selectedTag onSelectionChange selectableValues = selectableValueElems : List (Element msg) selectableValueElems = selectableValues + |> (\list -> + case searchText of + Nothing -> + list + + Just s -> + List.filter (\le -> String.contains (s |> String.toLower) (le.tag |> String.toLower)) list + ) |> List.map - (\( tag, content ) -> + (\dropdownElement -> viewListItem { icon = - if selectedTag == Just tag then + if selectedvalue == Just dropdownElement.value then html (Icon.check |> Icon.styled [ Icon.lg, Svg.Attributes.color (colorToSvg theme.colors.primaryHighlight) ] |> Icon.view) else none , label = - content + dropdownElement.displayElement , onClick = - onSelectionChange (Just tag) + onSelectionChange (Just dropdownElement.value) } ) in diff --git a/src/Morphir/Visual/Components/TypeBuilder.elm b/src/Morphir/Visual/Components/TypeBuilder.elm new file mode 100644 index 000000000..309e37655 --- /dev/null +++ b/src/Morphir/Visual/Components/TypeBuilder.elm @@ -0,0 +1,900 @@ +module Morphir.Visual.Components.TypeBuilder exposing (NewType, State, init, view) + +import Array +import Bootstrap.Form.Radio exposing (name) +import Dict +import Element exposing (Element, above, centerX, centerY, column, el, fill, fillPortion, height, padding, paddingEach, paddingXY, row, scrollbars, shrink, spacing, text, width) +import Element.Background as Background +import Element.Border as Border +import Element.Font as Font +import Element.Input as Input +import Html.Events +import Json.Decode as Decode +import List.Extra +import Morphir.IR.AccessControlled as AccessControlled exposing (Access(..)) +import Morphir.IR.FQName as FQName +import Morphir.IR.Module exposing (ModuleName) +import Morphir.IR.Name as Name exposing (Name) +import Morphir.IR.Package as Package exposing (PackageName) +import Morphir.IR.SDK.Basics exposing (boolType, floatType, intType) +import Morphir.IR.SDK.Decimal exposing (decimalType) +import Morphir.IR.SDK.String exposing (stringType) +import Morphir.IR.Type as Type exposing (Definition(..), Field, Type, record) +import Morphir.Visual.Common exposing (nameToTitleText) +import Morphir.Visual.Components.InputComponent as InputComponent +import Morphir.Visual.Components.Picklist as Picklist +import Morphir.Visual.Theme as Theme exposing (Theme) +import Ordering +import Morphir.IR.Path as Path + + +type alias State = + { typeName : String + , newModuleName : String + , createNewModule : Bool + , typePickerState : Picklist.State (Type.Definition ()) + , modulePickerState : Picklist.State ModuleName + , customTypeEditorState : CustomTypeEditorState + , recordTypeEditorState : RecordTypeEditorState + , showSaveIR : Bool + , documentation : String + , typeNameError : Maybe String + } + + +type alias CustomTypeEditorState = + { constructorNames : List Name + , currentlyEditedConstructor : String + , error : Maybe String + } + + +type alias RecordTypeEditorState = + { recordFields : List (Field ()) + , currentlyEditedFieldName : String + , currentlyEditedFieldType : Picklist.State (Type ()) + , currentlyEditedFieldOptional : Bool + , error : Maybe String + } + + +type alias Config msg = + { state : State + , onStateChange : State -> msg + , onTypeAdd : NewType -> msg + , onIRSave : msg + } + + +type alias NewType = + { moduleName : ModuleName + , name : Name + , definition : Type.Definition () + , access : Access + , documentation : String + } + + +type Msg + = UpdateTypeName String + | UpdateNewModuleName String + | ToggleNewModule + | TypePicklistChanged (Picklist.State (Type.Definition ())) + | ModulePicklistChanged (Picklist.State ModuleName) + | DocumentationChanged String + | ConstructorEditor ConstructorEditorMsg + | RecordEditor RecordEditorMsg + + +type ConstructorEditorMsg + = UpdateConstructorName String + | SaveConstructorName + | DeleteConstructorName Name + + +type RecordEditorMsg + = UpdateRecordFieldName String + | RecordTypePicklistChanged (Picklist.State (Type ())) + | DeleteField Name + | SaveField (Maybe (Type ())) + | ToggleFieldOptional Name Bool + | ToggleNewFieldOptional Bool + + +update : Msg -> State -> State +update typeBuildermsg state = + case typeBuildermsg of + UpdateTypeName n -> + { state + | typeName = n + , typeNameError = + if not <| isValidName [ n ] then + Just "This is not a valid name" + + else + Nothing + } + + UpdateNewModuleName n -> + { state + | newModuleName = n + } + + TypePicklistChanged newState -> + { state | typePickerState = newState } + + ModulePicklistChanged newState -> + { state | modulePickerState = newState } + + ConstructorEditor msg -> + let + customTypeEditorState = + state.customTypeEditorState + in + case msg of + UpdateConstructorName ctrName -> + { state + | customTypeEditorState = + { customTypeEditorState + | currentlyEditedConstructor = ctrName + } + } + + SaveConstructorName -> + let + ctrName : Name + ctrName = + Name.fromString customTypeEditorState.currentlyEditedConstructor + in + if + (not <| + List.member ctrName customTypeEditorState.constructorNames + ) + && isValidName ctrName + then + { state + | customTypeEditorState = + { customTypeEditorState + | constructorNames = (ctrName :: customTypeEditorState.constructorNames) |> List.sort + , currentlyEditedConstructor = "" + , error = Nothing + } + } + + else + { state + | customTypeEditorState = + { customTypeEditorState + | error = Just "This not a valid name" + } + } + + DeleteConstructorName ctrToDelete -> + { state + | customTypeEditorState = + { customTypeEditorState + | constructorNames = List.Extra.remove ctrToDelete customTypeEditorState.constructorNames + } + } + + RecordEditor msg -> + let + recordTypeEditorState = + state.recordTypeEditorState + in + case msg of + UpdateRecordFieldName fieldName -> + { state + | recordTypeEditorState = + { recordTypeEditorState + | currentlyEditedFieldName = fieldName + } + } + + RecordTypePicklistChanged newState -> + { state + | recordTypeEditorState = + { recordTypeEditorState + | currentlyEditedFieldType = newState + } + } + + DeleteField fieldName -> + { state + | recordTypeEditorState = + { recordTypeEditorState + | recordFields = List.filter (\field -> not (field.name == fieldName)) recordTypeEditorState.recordFields + } + } + + SaveField maybeTpe -> + let + fieldName : Name + fieldName = + Name.fromString recordTypeEditorState.currentlyEditedFieldName + + doesFieldExist : Name -> Bool + doesFieldExist fName = + recordTypeEditorState.recordFields |> List.any (\field -> field.name == fName) + in + case maybeTpe of + Just tpe -> + let + maybeOptionalType : Type () + maybeOptionalType = + if recordTypeEditorState.currentlyEditedFieldOptional then + makeOptional tpe + + else + tpe + in + if (not <| (doesFieldExist fieldName || String.isEmpty recordTypeEditorState.currentlyEditedFieldName)) && isValidName fieldName then + { state + | recordTypeEditorState = + { recordTypeEditorState + | recordFields = ({ name = fieldName, tpe = maybeOptionalType } :: recordTypeEditorState.recordFields) |> List.sortWith (Ordering.byField .name) + , currentlyEditedFieldName = "" + , error = Nothing + , currentlyEditedFieldType = Picklist.init Nothing + , currentlyEditedFieldOptional = False + } + } + + else + { state + | recordTypeEditorState = + { recordTypeEditorState + | error = Just "This is not a valid field name" + } + } + + Nothing -> + { state + | recordTypeEditorState = + { recordTypeEditorState + | error = Just "Please select a type" + } + } + + ToggleFieldOptional fieldName optional -> + let + toggleOptional : Field () -> Field () + toggleOptional field = + if field.name == fieldName then + if optional then + { field | tpe = makeOptional field.tpe } + + else + { field | tpe = removeOptional field.tpe } + + else + field + in + { state + | recordTypeEditorState = + { recordTypeEditorState + | recordFields = List.map toggleOptional recordTypeEditorState.recordFields + } + } + + ToggleNewFieldOptional optional -> + { state | recordTypeEditorState = { recordTypeEditorState | currentlyEditedFieldOptional = optional } } + + DocumentationChanged documentation -> + { state | documentation = documentation } + + ToggleNewModule -> + { state | createNewModule = not state.createNewModule } + + +init : Maybe ModuleName -> Bool -> State +init maybeModuleName showSaveIR = + { typeName = "" + , newModuleName = "" + , createNewModule = False + , typePickerState = Picklist.init Nothing + , modulePickerState = Picklist.init maybeModuleName + , customTypeEditorState = initCustomTypeEditor + , recordTypeEditorState = initRecordTypeEditorState + , showSaveIR = showSaveIR + , documentation = "" + , typeNameError = Nothing + } + + +initCustomTypeEditor : CustomTypeEditorState +initCustomTypeEditor = + { constructorNames = [] + , currentlyEditedConstructor = "" + , error = Nothing + } + + +initRecordTypeEditorState : RecordTypeEditorState +initRecordTypeEditorState = + { recordFields = [] + , currentlyEditedFieldName = "" + , currentlyEditedFieldType = Picklist.init Nothing + , currentlyEditedFieldOptional = False + , error = Nothing + } + + +view : Theme -> Config msg -> PackageName -> Package.Definition () (Type ()) -> ModuleName -> Element msg +view theme config packageName packageDef moduleName = + let + typeNameInput : Element msg + typeNameInput = + el [ above (el [ padding (Theme.smallPadding theme), Font.color theme.colors.mediumGray ] (text "Name")), width fill ] + (InputComponent.textInput + theme + [] + { onChange = \s -> config.onStateChange (update (UpdateTypeName s) config.state) + , text = config.state.typeName + , placeholder = Just (Input.placeholder [] (text "Name your new term")) + , label = Input.labelHidden "Type's name" + } + config.state.typeNameError + ) + + typePicklist : Element msg + typePicklist = + let + typeList : List { displayElement : Element msg, value : Definition (), tag : String } + typeList = + packageDef.modules + |> Dict.toList + |> List.concatMap + (\( mn, accessControlledModuleDef ) -> + accessControlledModuleDef.value.types + |> Dict.toList + |> List.map + (\( typeName, _ ) -> + createDropdownElement + theme + (Type.typeAliasDefinition [] (Type.Reference () (FQName.fQName packageName moduleName typeName) [])) + (typeName |> nameToTitleText) + (typeName |> nameToTitleText) + (modulePath mn) + ) + ) + |> List.sortWith (Ordering.byField .tag) + in + el [ above (el [ padding (Theme.smallPadding theme), Font.color theme.colors.mediumGray ] (text "Basis type")), width fill ] + (Picklist.view theme + { state = config.state.typePickerState + , onStateChange = \pickListState -> config.onStateChange (update (TypePicklistChanged pickListState) config.state) + } + (builtInTypes |> List.map (\( name, def ) -> createDropdownElement theme def name name "SDK")) + typeList + ) + + newModuleNameInput : Element msg + newModuleNameInput = + el [ above (el [ padding (Theme.smallPadding theme), Font.color theme.colors.mediumGray ] (text "New Module's name")), width fill ] + (InputComponent.textInput + theme + [] + { onChange = \s -> config.onStateChange (update (UpdateNewModuleName s) config.state) + , text = config.state.newModuleName + , placeholder = Just (Input.placeholder [] (text "Name your new module")) + , label = Input.labelHidden "New Module's name" + } + config.state.typeNameError + ) + + toggleNewModuleButton : Element msg + toggleNewModuleButton = + Input.button + [ padding 7 + , theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + ] + { onPress = Just (config.onStateChange (update ToggleNewModule config.state)) + , label = + if config.state.createNewModule then + text "Pick Existing Module" + + else + text "Create New Module" + } + + getModuleName : ModuleName + getModuleName = + if config.state.createNewModule then + Path.fromString config.state.newModuleName + else + config.state.modulePickerState.selectedValue |> Maybe.withDefault [] + + modulePicklist : Element msg + modulePicklist = + let + getIntermediaryModules : ModuleName -> List ModuleName + getIntermediaryModules mn = + List.foldl + (\m soFar -> + case m of + [] -> + [ [ m ] ] + + _ -> + let + lastSubPath = + List.reverse (List.head soFar |> Maybe.withDefault []) + + newSubPath = + m :: lastSubPath + in + List.reverse newSubPath :: soFar + ) + [] + mn + + moduleList : List { displayElement : Element msg, value : ModuleName, tag : String } + moduleList = + (packageDef.modules + |> Dict.keys + |> List.concatMap getIntermediaryModules + |> List.Extra.unique + |> List.map + (\mn -> + createDropdownElement + theme + mn + (List.map nameToTitleText mn |> List.reverse |> List.intersperse " " |> List.foldl (++) "") + (mn |> List.reverse |> List.head |> Maybe.withDefault [] |> nameToTitleText) + (modulePath mn) + ) + ) + |> List.sortWith (Ordering.byField .tag) + in + el [ above (el [ padding (Theme.smallPadding theme), Font.color theme.colors.mediumGray ] (text "Module")), width fill ] + (Picklist.view theme + { state = config.state.modulePickerState + , onStateChange = \pickListState -> config.onStateChange (update (ModulePicklistChanged pickListState) config.state) + } + [] + moduleList + ) + + saveButton : Element msg + saveButton = + Input.button + [ padding 7 + , theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + ] + { onPress = Just config.onIRSave + , label = text "Save model" + } + + documentationInput : Element msg + documentationInput = + InputComponent.multiLine theme + [ width fill ] + { onChange = \txt -> config.onStateChange (update (DocumentationChanged txt) config.state) + , text = config.state.documentation + , placeholder = Just (Input.placeholder [] (text "Add some documentation explaining the purpose of this term...")) + , spellcheck = False + , label = Input.labelAbove [] <| text "Documentation" + } + Nothing + + addTypeButton : Element msg + addTypeButton = + let + addTypeMessage : Maybe msg + addTypeMessage = + let + addType : Type.Definition () -> NewType + addType def = + { name = Name.fromString config.state.typeName + , definition = + case def of + CustomTypeDefinition _ _ -> + Type.customTypeDefinition [] (AccessControlled.public <| Dict.fromList (List.map (\n -> Tuple.pair n []) config.state.customTypeEditorState.constructorNames)) + + TypeAliasDefinition _ (Type.Record _ _) -> + Type.typeAliasDefinition [] (record () config.state.recordTypeEditorState.recordFields) + + _ -> + def + , access = Public + , documentation = config.state.documentation + , moduleName = getModuleName + } + in + if (config.state.typeName |> String.isEmpty) || not ([ config.state.typeName ] |> isValidName) then + Nothing + + else + config.state.typePickerState.selectedValue |> Maybe.map (addType >> config.onTypeAdd) + in + Input.button + [ padding 7 + , theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + ] + { onPress = addTypeMessage + , label = text "Add new term" + } + in + column + [ spacing (Theme.largeSpacing theme) + , padding (Theme.largePadding theme) + , height fill + , width fill + ] + [ row + [ spacing (Theme.mediumSpacing theme) + ] + [ typeNameInput + , el [ Font.bold ] (text " is a kind of ") + , typePicklist + , el [ Font.bold ] (text " in ") + , column [ spacing (Theme.mediumPadding theme), width fill ] + [ if config.state.createNewModule then + newModuleNameInput + + else + modulePicklist + , toggleNewModuleButton + ] + ] + , case config.state.typePickerState.selectedValue of + Just (CustomTypeDefinition _ _) -> + column + [ spacing (Theme.smallSpacing theme) ] + [ el [ Font.bold ] (text " which can be one of: "), customTypeEditor theme config ] + + Just (TypeAliasDefinition _ (Type.Record _ _)) -> + column + [ spacing (Theme.smallSpacing theme) ] + [ el [ Font.bold ] (text " with the following fields: "), recordTypeEditor theme config packageName packageDef moduleName ] + + _ -> + Element.none + , documentationInput + , row [ spacing <| Theme.largeSpacing theme ] + (el [ paddingXY 0 (Theme.mediumPadding theme) ] addTypeButton + :: (if config.state.showSaveIR then + [ el [ paddingXY 0 (Theme.mediumPadding theme) ] saveButton ] + + else + [] + ) + ) + ] + + +sdkTypes : List ( String, Type () ) +sdkTypes = + [ ( "Boolean", boolType () ) + , ( "Decimal", decimalType () ) + , ( "Integer", intType () ) + , ( "Floating Point Number", floatType () ) + , ( "Text", stringType () ) + ] + + +builtInTypes : List ( String, Type.Definition () ) +builtInTypes = + let + customType : List ( String, Type.Definition () ) + customType = + [ ( "Enum", Type.customTypeDefinition [] (AccessControlled.public Dict.empty) ) ] + + recordType : List ( String, Type.Definition () ) + recordType = + [ ( "Record", Type.typeAliasDefinition [] (record () []) ) ] + in + customType ++ recordType ++ (sdkTypes |> List.map (Tuple.mapSecond (Type.typeAliasDefinition []))) + + +createDropdownElement : Theme -> a -> String -> String -> String -> { displayElement : Element msg, tag : String, value : a } +createDropdownElement theme def tag displayName path = + { displayElement = + column [ padding (Theme.smallPadding theme), Element.clip, width fill ] + [ displayName |> Theme.ellipseText + , el [ Font.color theme.colors.mediumGray, Font.size (Theme.scaled 0 theme), paddingXY 0 2 ] (Theme.ellipseText path) + ] + , tag = tag + , value = def + } + + +modulePath : ModuleName -> String +modulePath mn = + List.map nameToTitleText mn |> List.reverse |> List.intersperse "> " |> List.foldl (++) "" + + +customTypeEditor : Theme -> Config msg -> Element msg +customTypeEditor theme config = + let + constructorNames : Element msg + constructorNames = + let + deleteConstructorBtn : Name -> Element msg + deleteConstructorBtn ctrName = + Input.button + [ theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + , padding 2 + ] + { onPress = Just <| config.onStateChange (update (ConstructorEditor <| DeleteConstructorName ctrName) config.state) + , label = text " x " + } + in + if List.isEmpty config.state.customTypeEditorState.constructorNames then + Element.none + + else + List.map + (\n -> row [ spacing (Theme.smallSpacing theme) ] [ el [ Font.bold, Theme.borderBottom 1, Border.color theme.colors.mediumGray ] (text <| nameToTitleText n), deleteConstructorBtn n ]) + config.state.customTypeEditorState.constructorNames + ++ [ el [ Font.bold ] (text "or") ] + |> column [ spacing <| Theme.smallSpacing theme, padding <| Theme.smallPadding theme ] + + ctrNameEditor : Element msg + ctrNameEditor = + InputComponent.textInput + theme + [ onEnter <| config.onStateChange (update (ConstructorEditor SaveConstructorName) config.state) ] + { onChange = \s -> config.onStateChange (update (ConstructorEditor <| UpdateConstructorName s) config.state) + , text = config.state.customTypeEditorState.currentlyEditedConstructor + , placeholder = Just (Input.placeholder [] (text "Name...")) + , label = Input.labelHidden "Next constructor name" + } + config.state.customTypeEditorState.error + + ctrSaveButton : Element msg + ctrSaveButton = + Input.button + [ theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + , padding (Theme.smallPadding theme) + ] + { onPress = Just <| config.onStateChange (update (ConstructorEditor SaveConstructorName) config.state) + , label = text " + " + } + in + column [ paddingXY (Theme.smallPadding theme) (Theme.mediumPadding theme), spacing <| Theme.mediumSpacing theme ] [ constructorNames, row [ spacing (Theme.smallSpacing theme) ] [ ctrNameEditor, ctrSaveButton ] ] + + +recordTypeEditor : Theme -> Config msg -> PackageName -> Package.Definition () (Type ()) -> ModuleName -> Element msg +recordTypeEditor theme config packageName packageDef moduleName = + let + elementList : List (Array.Array (Element msg)) + elementList = + let + deleteFieldBtn : Name -> Element msg + deleteFieldBtn fieldName = + Input.button + [ theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + , padding 2 + , centerX + , centerY + , Font.center + ] + { onPress = Just <| config.onStateChange (update (RecordEditor <| DeleteField fieldName) config.state) + , label = el [ width shrink, centerX, centerY, Font.center ] <| text " x " + } + + leftColumn : Field () -> Element msg + leftColumn field = + row [ Font.bold ] [ nameToTitleText field.name |> Theme.ellipseText ] + + rightColumn : Field () -> Element msg + rightColumn field = + field.tpe |> Type.toString |> String.split "." |> List.Extra.last |> Maybe.withDefault "" |> text + + checkbox : Field () -> Element msg + checkbox f = + isOptionalCheckbox + theme + (isOptional f.tpe) + (\b -> config.onStateChange (update (RecordEditor <| ToggleFieldOptional f.name b) config.state)) + + fieldSaveButton : Element msg + fieldSaveButton = + Input.button + [ padding 7 + , theme |> Theme.borderRounded + , Background.color theme.colors.darkest + , Font.color theme.colors.lightest + , Font.bold + , Font.size theme.fontSize + ] + { onPress = Just <| config.onStateChange (update (RecordEditor <| SaveField config.state.recordTypeEditorState.currentlyEditedFieldType.selectedValue) config.state) + , label = text "Add field" + } + + newFieldOptionalCheckbox : Element msg + newFieldOptionalCheckbox = + isOptionalCheckbox + theme + config.state.recordTypeEditorState.currentlyEditedFieldOptional + (\b -> config.onStateChange (update (RecordEditor <| ToggleNewFieldOptional b) config.state)) + + fieldNameEditor : Element msg + fieldNameEditor = + InputComponent.textInput + theme + [ width fill ] + { onChange = \s -> config.onStateChange (update (RecordEditor <| UpdateRecordFieldName s) config.state) + , text = config.state.recordTypeEditorState.currentlyEditedFieldName + , placeholder = Just (Input.placeholder [] (text "Name...")) + , label = Input.labelHidden "Next field name" + } + config.state.recordTypeEditorState.error + + typePicklist : Element msg + typePicklist = + let + typeList : List { displayElement : Element msg, value : Type (), tag : String } + typeList = + packageDef.modules + |> Dict.toList + |> List.concatMap + (\( mn, accessControlledModuleDef ) -> + accessControlledModuleDef.value.types + |> Dict.toList + |> List.map + (\( typeName, _ ) -> + createDropdownElement + theme + (Type.Reference () (FQName.fQName packageName moduleName typeName) []) + (typeName |> nameToTitleText) + (typeName |> nameToTitleText) + (modulePath mn) + ) + ) + |> List.sortWith (Ordering.byField .tag) + in + el [ width fill ] + (Picklist.view theme + { state = config.state.recordTypeEditorState.currentlyEditedFieldType + , onStateChange = \pickListState -> config.onStateChange (update (RecordEditor (RecordTypePicklistChanged pickListState)) config.state) + } + (sdkTypes |> List.map (\( name, def ) -> createDropdownElement theme def name name "SDK")) + typeList + ) + in + List.map (\f -> Array.fromList [ checkbox f, leftColumn f, rightColumn f, deleteFieldBtn f.name ]) config.state.recordTypeEditorState.recordFields + ++ [ Array.fromList [ newFieldOptionalCheckbox, fieldNameEditor, typePicklist, fieldSaveButton ] ] + + fieldTable : Element msg + fieldTable = + let + header title = + el [ paddingXY 0 (Theme.largePadding theme), Font.color theme.colors.mediumGray ] (text title) + + getColumnElement : Int -> Array.Array (Element msg) -> Element msg + getColumnElement index = + Array.get index >> Maybe.withDefault Element.none + in + Element.table + [ width fill + , paddingEach { bottom = Theme.smallPadding theme, top = 0, left = 0, right = 0 } + , spacing <| Theme.mediumSpacing theme + ] + { columns = + [ { header = header "Optional?" + , width = fillPortion 2 + , view = + \f -> + getColumnElement 0 f + } + , { header = header "Field Name" + , width = fillPortion 5 + , view = + \f -> + getColumnElement 1 f + } + , { header = header "Field Type" + , width = fillPortion 5 + , view = + \f -> + getColumnElement 2 f + } + , { header = Element.none + , width = shrink + , view = + \f -> + getColumnElement 3 f + } + ] + , data = elementList + } + in + column [ paddingXY (Theme.smallPadding theme) (Theme.mediumPadding theme), spacing <| Theme.mediumSpacing theme ] [ el [ Font.bold ] (text "{"), fieldTable, el [ Font.bold ] (text "}") ] + + +onEnter : msg -> Element.Attribute msg +onEnter msg = + Element.htmlAttribute + (Html.Events.on "keyup" + (Decode.field "key" Decode.string + |> Decode.andThen + (\key -> + if key == "Enter" then + Decode.succeed msg + + else + Decode.fail "Not the enter key" + ) + ) + ) + + +isOptional : Type () -> Bool +isOptional tpe = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ _ ] -> + True + + _ -> + False + + +makeOptional : Type () -> Type () +makeOptional tpe = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ tpe ] + + +removeOptional : Type () -> Type () +removeOptional tpe = + case tpe of + Type.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "maybe" ] ], [ "maybe" ] ) [ t ] -> + t + + _ -> + tpe + + +isOptionalCheckbox : Theme -> Bool -> (Bool -> msg) -> Element msg +isOptionalCheckbox theme isChecked message = + InputComponent.checkBox theme + [] + { onChange = \s -> message s + , checked = isChecked + , label = Input.labelHidden "is type optional?" + } + + +isValidName : Name -> Bool +isValidName name = + if List.isEmpty name then + False + + else + case name |> List.head of + Nothing -> + False + + Just str -> + case str |> String.toList |> List.head of + Just char -> + Char.isAlpha char + + Nothing -> + False diff --git a/src/Morphir/Visual/Theme.elm b/src/Morphir/Visual/Theme.elm index 7a804ad8c..20728ec92 100644 --- a/src/Morphir/Visual/Theme.elm +++ b/src/Morphir/Visual/Theme.elm @@ -7,6 +7,7 @@ import Element.Font as Font exposing (center) import Element.Input as Input import Html exposing (div, text) import Html.Attributes exposing (style) +import Element exposing (shrink) type alias Theme = @@ -89,9 +90,9 @@ fromConfig maybeConfig = , mediumGray = rgb 0.5 0.5 0.5 , lightGray = rgba 0.9 0.9 0.9 0.5 , brandPrimary = rgb 0 0.639 0.882 - , brandPrimaryLight = rgba 0 0.639 0.882 0.3 + , brandPrimaryLight = rgba 0 0.639 0.882 0.2 , brandSecondary = rgb 1 0.411 0 - , brandSecondaryLight = rgba 1 0.411 0 0.3 + , brandSecondaryLight = rgba 1 0.411 0 0.2 , warning = rgba255 238 210 2 0.9 , highlighted = rgb255 0 163 255 , notHighlighted = rgb255 120 120 120 @@ -224,11 +225,11 @@ twoColumnTableView tableData leftView rightView = ] { columns = [ { header = none - , width = fill + , width = shrink , view = leftView } , { header = none - , width = fill + , width = shrink , view = rightView } ] diff --git a/src/Morphir/Visual/ValueEditor.elm b/src/Morphir/Visual/ValueEditor.elm index ed0499412..6cd8d81ed 100644 --- a/src/Morphir/Visual/ValueEditor.elm +++ b/src/Morphir/Visual/ValueEditor.elm @@ -60,6 +60,10 @@ import Element , table , text , width + , centerX + , shrink + , minimum + , maximum ) import Element.Background as Background import Element.Border as Border @@ -71,7 +75,7 @@ import Morphir.IR.Distribution as Distribution exposing (Distribution) import Morphir.IR.FQName exposing (FQName) import Morphir.IR.Literal exposing (Literal(..)) import Morphir.IR.Name as Name exposing (Name) -import Morphir.IR.Path as Path exposing (Path) +import Morphir.IR.Path as Path import Morphir.IR.SDK.Basics as Basics import Morphir.IR.SDK.Char as Basics import Morphir.IR.SDK.Decimal as Decimal @@ -88,9 +92,10 @@ import Morphir.Visual.Components.DatePickerComponent as DatePicker import Morphir.Visual.Components.FieldList as FieldList import Morphir.Visual.Components.InputComponent as InputComponent import Morphir.Visual.Components.Picklist as Picklist -import Morphir.Visual.Theme exposing (Theme) +import Morphir.Visual.Theme as Theme exposing (Theme, scaled) import Svg import Svg.Attributes +import Morphir.Visual.Theme as Theme {-| Type that represents the state of the value editor. It's made up of the following pieces of information: @@ -580,7 +585,7 @@ view theme ir valueType updateEditorState editorState = let baseStyle : List (Element.Attribute msg) baseStyle = - [ width <| Element.fillPortion 3 + [ width (fill |> minimum (scaled 12 theme) |> maximum (scaled 20 theme)) , height fill , Events.onLoseFocus (updateEditorState (initEditorState ir valueType editorState.lastValidValue)) @@ -588,7 +593,12 @@ view theme ir valueType updateEditorState editorState = labelStyle : List (Element.Attr () msg) labelStyle = - [ Background.color (rgb 0.2 0.3 0.4), centerY, Font.color (rgb 0.7 0.7 0.7), paddingEach { top = 5, bottom = 5, right = 10, left = 0 } ] + [ centerY + , centerX + , paddingEach { top = 5, bottom = 5, right = 10, left = 0 } + , width (shrink |> minimum (Theme.scaled 10 theme) |> maximum (Theme.scaled 15 theme)) + , Font.italic + ] in case editorState.componentState of TextEditor currentText -> @@ -693,7 +703,7 @@ view theme ir valueType updateEditorState editorState = editorState.errorState , if editorState.defaultValueCheckbox.show then InputComponent.checkBox theme - [ center ] + [ center, width shrink ] { label = Input.labelRight (labelStyle ++ [ Background.color <| rgba 0 0 0 0 ]) (text "empty (\"\")") , checked = editorState.defaultValueCheckbox.checked , onChange = @@ -730,21 +740,20 @@ view theme ir valueType updateEditorState editorState = RecordEditor fieldEditorStates -> row [] <| - [ el [ Background.color (rgb 0.2 0.3 0.4), centerY, Font.color (rgb 0.7 0.7 0.7), paddingXY 10 5 ] (text "record") + [ el [ Font.italic, paddingXY 10 5 ] (text "record") , el - [ padding 7 - , Background.color (rgb 0.7 0.8 0.9) - , Border.rounded 7 + [ padding <| Theme.largePadding theme + , Background.color theme.colors.brandPrimaryLight + , Theme.borderRounded theme ] - (FieldList.view + (FieldList.view theme (fieldEditorStates |> Dict.toList |> List.map (\( fieldName, ( fieldType, fieldEditorState ) ) -> ( fieldName , el - [ width fill - , height fill + [ height fill , centerY ] (view theme @@ -866,7 +875,7 @@ view theme ir valueType updateEditorState editorState = itemEditorState in row [] <| - [ el [ Background.color (rgb 0.2 0.3 0.4), centerY, Font.color (rgb 0.7 0.7 0.7), paddingXY 0 5 ] (text "optional ") + [ el [ centerY, paddingXY 0 5, Font.italic ] (text "optional ") , itemEditor (maybeItemEditorState |> Maybe.withDefault (initEditorState ir itemType Nothing) @@ -1050,7 +1059,7 @@ view theme ir valueType updateEditorState editorState = { header = el [ width fill, height fill, paddingXY 10 5, Font.bold, Background.color (rgb 1 1 1) ] (el [ width fill, center ] (text (columnName |> Name.toHumanWords |> String.join " "))) - , width = fill + , width = shrink , view = \( rowIndex, rowEditorStates ) -> let @@ -1080,6 +1089,7 @@ view theme ir valueType updateEditorState editorState = el [ width fill , height fill + , padding 1 , Background.color (rgb 1 1 1) , inFront (addButton (emptyRowEditors :: cellEditorStates)) , if rowIndex == List.length cellEditorStates - 1 then @@ -1327,7 +1337,7 @@ viewCustomTypeEditor theme labelStyle ir updateEditorState editorState (( packag { state = customTypeEditorState.constructorPicklistState , onStateChange = \constructorPicklistState -> - case constructorPicklistState |> Picklist.getSelectedTag of + case constructorPicklistState |> Picklist.getSelectedValue of Nothing -> updateEditorState { componentState = @@ -1366,10 +1376,14 @@ viewCustomTypeEditor theme labelStyle ir updateEditorState editorState (( packag (constructors |> Dict.toList |> List.map - (\( ctorName, ctorArgs ) -> - ( ( ctorName, ctorArgs ), text (ctorName |> Name.toHumanWordsTitle |> String.join " ") ) + (\(( ctorName, ctorArgs ) as ctor) -> + ( {tag = ctorName |> Name.toTitleCase + , value = ctor + , displayElement = el [padding <| Theme.smallPadding theme, width fill] (Theme.ellipseText (ctorName |> Name.toHumanWordsTitle |> String.join " ")) + } ) ) ) + [] viewArguments : List (Element msg) viewArguments = @@ -1395,7 +1409,7 @@ viewCustomTypeEditor theme labelStyle ir updateEditorState editorState (( packag selectedConstructorResult : Result Error (Value () ()) selectedConstructorResult = customTypeEditorState.constructorPicklistState - |> Picklist.getSelectedTag + |> Picklist.getSelectedValue |> Maybe.map (\( ctorName, _ ) -> Value.Constructor () ( packageName, moduleName, ctorName ) diff --git a/src/Morphir/Visual/ViewApply.elm b/src/Morphir/Visual/ViewApply.elm index 7efe454e4..258f81f75 100644 --- a/src/Morphir/Visual/ViewApply.elm +++ b/src/Morphir/Visual/ViewApply.elm @@ -1,10 +1,11 @@ module Morphir.Visual.ViewApply exposing (view) import Dict exposing (Dict) -import Element exposing (Element, above, centerX, centerY, el, fill, moveUp, padding, row, spacing, text, width) +import Element exposing (Element, above, centerX, centerY, el, fill, htmlAttribute, moveUp, padding, row, spacing, text, width) import Element.Background as Background import Element.Border as Border import Element.Font as Font +import Html.Attributes exposing (style) import Morphir.IR.Distribution as Distribution import Morphir.IR.FQName exposing (FQName) import Morphir.IR.Name as Name @@ -15,6 +16,7 @@ import Morphir.Type.Infer as Infer import Morphir.Value.Error exposing (Error(..)) import Morphir.Value.Interpreter exposing (complete, evaluateFunctionValue, evaluateValue) import Morphir.Visual.Common exposing (nameToText, tooltip) +import Morphir.Visual.Components.DecisionTree as DecisionTree import Morphir.Visual.Components.DrillDownPanel as DrillDownPanel exposing (Depth) import Morphir.Visual.Components.FieldList as FieldList import Morphir.Visual.Config exposing (Config, DrillDownFunctions(..), drillDownContains, evalIfPathTaken) @@ -23,8 +25,8 @@ import Morphir.Visual.Theme as Theme exposing (borderRounded, smallPadding, smal import Morphir.Visual.ViewList as ViewList -view : Config msg -> (Config msg -> Value.Definition () (Type ()) -> Element msg) -> (EnrichedValue -> Element msg) -> EnrichedValue -> List EnrichedValue -> Element msg -view config viewDefinitionBody viewValue functionValue argValues = +view : Config msg -> (Config msg -> Value.Definition () (Type ()) -> Element msg) -> (EnrichedValue -> Element msg) -> EnrichedValue -> List EnrichedValue -> EnrichedValue -> Element msg +view config viewDefinitionBody viewValue functionValue argValues applyValue = let styles : List (Element.Attribute msg) styles = @@ -52,7 +54,7 @@ view config viewDefinitionBody viewValue functionValue argValues = viewFunctionValue : FQName -> Element msg viewFunctionValue fqName = - el [ tooltip above (functionOutput fqName) ] <| viewValue functionValue + el [ tooltip above (functionOutput config fqName functionValue argValues viewValue) ] <| viewValue functionValue viewArgumentList : List (Element msg) viewArgumentList = @@ -74,60 +76,12 @@ view config viewDefinitionBody viewValue functionValue argValues = ] (viewValue v) ) - - functionOutput : FQName -> Element msg - functionOutput fqName = - let - variables : List (Maybe RawValue) - variables = - case config.ir |> Distribution.lookupValueDefinition fqName of - Just valueDef -> - Dict.fromList (List.map2 (\( name, _, _ ) argValue -> ( name, argValue |> evalIfPathTaken config )) valueDef.inputTypes argValues) |> Dict.values - - Nothing -> - [] - - viewRawValue : RawValue -> Element msg - viewRawValue rawValue = - case fromRawValue config.ir rawValue of - Ok typedValue -> - el [ centerY ] (viewValue typedValue) - - Err error -> - el [ centerX, centerY ] (text (Infer.typeErrorToMessage error)) - - popupstyles : List (Element.Attribute msg) - popupstyles = - [ Background.color config.state.theme.colors.lightest - , Font.bold - , Font.center - , config.state.theme |> borderRounded - , Border.width 1 - , smallPadding config.state.theme |> padding - ] - in - case evaluateFunctionValue complete config.nativeFunctions config.ir fqName variables of - Ok value -> - el popupstyles (viewRawValue value) - - Err firstError -> - case firstError of - ReferenceNotFound _ -> - case evaluateValue complete config.nativeFunctions config.ir config.state.variables (List.map toRawValue argValues) (toRawValue functionValue) of - Ok value -> - el popupstyles (viewRawValue value) - - Err err -> - Element.none - - _ -> - Element.none in case ( functionValue, argValues ) of ( (Value.Constructor _ fQName) as constr, _ ) -> case config.ir |> Distribution.lookupTypeSpecification (config.ir |> Distribution.resolveAliases fQName) of Just (Type.TypeAliasSpecification _ (Type.Record _ fields)) -> - FieldList.view + FieldList.view config.state.theme (List.map2 (\field arg -> ( field.name @@ -162,6 +116,15 @@ view config viewDefinitionBody viewValue functionValue argValues = , text ")" ] + ( Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], _, [ "map" ] ), [ _, _ ] ) -> + pipeVisualisation config applyValue viewValue + + ( Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], _, [ "filter" ] ), [ _, _ ] ) -> + pipeVisualisation config applyValue viewValue + + ( Value.Reference _ ( [ [ "morphir" ], [ "s", "d", "k" ] ], _, [ "filter", "map" ] ), [ _, _ ] ) -> + pipeVisualisation config applyValue viewValue + -- possibly binary operator ( Value.Reference _ (( [ [ "morphir" ], [ "s", "d", "k" ] ], moduleName, localName ) as fqName), [ argValues1, argValues2 ] ) -> let @@ -289,7 +252,7 @@ view config viewDefinitionBody viewValue functionValue argValues = _ -> row ([ Border.color config.state.theme.colors.gray, Border.width 1, smallPadding config.state.theme |> padding, config.state.theme |> borderRounded ] ++ styles) - [ viewFunctionValue ( [], [], [] ) + [ viewValue functionValue , row [ width fill, centerX, smallSpacing config.state.theme |> spacing ] viewArgumentList ] @@ -311,3 +274,107 @@ inlineBinaryOperators = , ( "Basics.notEqual", "≠" ) , ( "Basics.power", "^" ) ] + + +functionOutput : Config msg -> FQName -> EnrichedValue -> List EnrichedValue -> (EnrichedValue -> Element msg) -> Element msg +functionOutput config fqName functionValue argValues viewValue = + let + variables : List (Maybe RawValue) + variables = + case config.ir |> Distribution.lookupValueDefinition fqName of + Just valueDef -> + Dict.fromList (List.map2 (\( name, _, _ ) argValue -> ( name, argValue |> evalIfPathTaken config )) valueDef.inputTypes argValues) |> Dict.values + + Nothing -> + [] + + viewRawValue : RawValue -> Element msg + viewRawValue rawValue = + case fromRawValue config.ir rawValue of + Ok typedValue -> + el [ centerY ] (viewValue typedValue) + + Err error -> + el [ centerX, centerY ] (text (Infer.typeErrorToMessage error)) + + popupstyles : List (Element.Attribute msg) + popupstyles = + [ Background.color config.state.theme.colors.lightest + , Font.bold + , Font.center + , config.state.theme |> borderRounded + , Border.width 1 + , smallPadding config.state.theme |> padding + ] + in + case evaluateFunctionValue config.nativeFunctions config.ir fqName variables of + Ok value -> + el popupstyles (viewRawValue value) + + Err firstError -> + case firstError of + ReferenceNotFound _ -> + case evaluateValue config.nativeFunctions config.ir config.state.variables (List.map toRawValue argValues) (toRawValue functionValue) of + Ok value -> + el popupstyles (viewRawValue value) + + Err err -> + Element.none + + _ -> + Element.none + + +pipeVisualisation : Config msg -> EnrichedValue -> (EnrichedValue -> Element msg) -> Element msg +pipeVisualisation config applyValue viewValue = + let + getMapsRec : EnrichedValue -> List (Element msg) + getMapsRec v = + let + recursiveCall : FQName -> EnrichedValue -> EnrichedValue -> EnrichedValue -> String -> List (Element msg) + recursiveCall currentFQName currentFunctionValue currentFunction src label = + getMapsRec src + ++ [ Element.column + [ Border.width 2 + , Border.color config.state.theme.colors.brandSecondaryLight + , Theme.borderRounded config.state.theme + ] + [ el [ Font.color config.state.theme.colors.mediumGray, padding 3, Element.centerX, Element.centerY ] (text label) + , viewValue currentFunction + ] + , arrow currentFQName currentFunctionValue [ currentFunction, src ] + ] + in + case v of + Value.Apply _ applyFunction applyArgs -> + case Value.uncurryApply applyFunction applyArgs of + ( (Value.Reference _ (( [ [ "morphir" ], [ "s", "d", "k" ] ], _, [ "map" ] ) as fqName)) as mapFunctionValue, [ mapfunc, source ] ) -> + recursiveCall fqName mapFunctionValue mapfunc source "map" + + ( (Value.Reference _ (( [ [ "morphir" ], [ "s", "d", "k" ] ], _, [ "filter" ] ) as fqName)) as mapFunctionValue, [ mapfunc, source ] ) -> + recursiveCall fqName mapFunctionValue mapfunc source "filter" + + ( (Value.Reference _ (( [ [ "morphir" ], [ "s", "d", "k" ] ], _, [ "filter", "map" ] ) as fqName)) as mapFunctionValue, [ mapfunc, source ] ) -> + recursiveCall fqName mapFunctionValue mapfunc source "filter & map" + + _ -> + [ viewValue v ] + + _ -> + [ viewValue v + , arrow ( [], [], [] ) v [] + ] + + arrow : FQName -> EnrichedValue -> List EnrichedValue -> Element msg + arrow fqName mapFunctionValue args = + el + [ Element.centerX + , Element.centerY + , tooltip Element.below (functionOutput config fqName mapFunctionValue args viewValue) + , htmlAttribute (style "z-index" "10000") + , width (Element.shrink |> Element.minimum (config.state.theme.fontSize * 3) |> Element.maximum (config.state.theme.fontSize * 5)) + ] + <| + DecisionTree.rightArrow config False + in + row [ spacing <| Theme.smallSpacing config.state.theme ] <| getMapsRec applyValue ++ [ el [ Font.italic ] <| text " output " ] diff --git a/src/Morphir/Visual/ViewLambda.elm b/src/Morphir/Visual/ViewLambda.elm index 157d42eee..6a85e84e0 100644 --- a/src/Morphir/Visual/ViewLambda.elm +++ b/src/Morphir/Visual/ViewLambda.elm @@ -9,16 +9,18 @@ import Morphir.IR.Value as Value exposing (Pattern(..), Value) import Morphir.Visual.Common exposing (nameToText) import Morphir.Visual.Config exposing (Config, HighlightState(..)) import Morphir.Visual.EnrichedValue exposing (EnrichedValue) -import Morphir.Visual.Theme exposing (mediumPadding, smallPadding) +import Morphir.Visual.Theme exposing (mediumPadding, smallPadding, borderRounded) import Morphir.Visual.ViewLiteral as ViewLiteral view : Config msg -> (Config msg -> EnrichedValue -> Element msg) -> Pattern ( Int, Type () ) -> Value () ( Int, Type () ) -> Element msg view config viewValue pattern val = let + styles : List (Element.Attribute msg) styles = - [ Background.color config.state.theme.colors.backgroundColor, smallPadding config.state.theme |> padding, Border.rounded 6 ] + [ Background.color config.state.theme.colors.backgroundColor, smallPadding config.state.theme |> padding, borderRounded config.state.theme ] + viewHelper : Pattern a -> List (Element msg) viewHelper p = case p of Value.WildcardPattern _ -> diff --git a/src/Morphir/Visual/ViewRecord.elm b/src/Morphir/Visual/ViewRecord.elm index 05be86cf9..8450dab04 100644 --- a/src/Morphir/Visual/ViewRecord.elm +++ b/src/Morphir/Visual/ViewRecord.elm @@ -1,14 +1,13 @@ module Morphir.Visual.ViewRecord exposing (..) import Dict exposing (Dict) -import Element exposing (Element, el, none, padding, rgb) +import Element exposing (Element, el, none, padding) import Element.Background as Background -import Element.Border as Border import Morphir.IR.Name exposing (Name) import Morphir.Visual.Components.FieldList as FieldList import Morphir.Visual.Config exposing (Config) import Morphir.Visual.EnrichedValue exposing (EnrichedValue) -import Morphir.Visual.Theme exposing (smallPadding) +import Morphir.Visual.Theme exposing (smallPadding, borderRounded) view : Config msg -> (EnrichedValue -> Element msg) -> Dict Name EnrichedValue -> Element msg @@ -23,7 +22,7 @@ view config viewValue items = else el [ smallPadding config.state.theme |> padding - , Background.color (rgb 0.7 0.8 0.9) - , Border.rounded 7 + , Background.color config.state.theme.colors.brandPrimaryLight + , borderRounded config.state.theme ] - (FieldList.view fields) + (FieldList.view config.state.theme fields) diff --git a/src/Morphir/Visual/ViewValue.elm b/src/Morphir/Visual/ViewValue.elm index 845d6750c..b644cde69 100644 --- a/src/Morphir/Visual/ViewValue.elm +++ b/src/Morphir/Visual/ViewValue.elm @@ -19,10 +19,11 @@ import Morphir.Type.Infer as Infer exposing (TypeError) import Morphir.Visual.BoolOperatorTree as BoolOperatorTree exposing (BoolOperatorTree) import Morphir.Visual.Common exposing (nameToText) import Morphir.Visual.Components.AritmeticExpressions as ArithmeticOperatorTree exposing (ArithmeticOperatorTree) +import Morphir.Visual.Components.DecisionTree as DecisionTree import Morphir.Visual.Components.DrillDownPanel as DrillDownPanel import Morphir.Visual.Config as Config exposing (Config, DrillDownFunctions(..), drillDownContains) import Morphir.Visual.EnrichedValue exposing (EnrichedValue, fromRawValue, fromTypedValue, getId) -import Morphir.Visual.Theme exposing (mediumPadding, mediumSpacing, smallPadding, smallSpacing) +import Morphir.Visual.Theme as Theme exposing (mediumPadding, mediumSpacing, smallPadding, smallSpacing) import Morphir.Visual.ViewApply as ViewApply import Morphir.Visual.ViewArithmetic as ViewArithmetic import Morphir.Visual.ViewBoolOperatorTree as ViewBoolOperatorTree @@ -258,27 +259,29 @@ viewValueByLanguageFeature config value = _ -> defaultFieldDisplay fieldName - Value.Apply _ fun arg -> + (Value.Apply _ fun arg) as applyValue -> let ( function, args ) = Value.uncurryApply fun arg in - ViewApply.view config definitionBody (viewValue config) function args + + + ViewApply.view config definitionBody (viewValue config) function args applyValue Value.LetDefinition _ _ _ _ -> let unnest : Config msg -> EnrichedValue -> ( List ( Name, Element msg ), Element msg ) - unnest conf v = + unnest configWithLetDefsSoFar v = case v of Value.LetDefinition _ defName def inVal -> let currentState = - conf.state + configWithLetDefsSoFar.state newState = { currentState | variables = - conf + configWithLetDefsSoFar |> Config.evaluate (def |> Value.mapDefinitionAttributes (always ()) (always ()) @@ -310,12 +313,12 @@ viewValueByLanguageFeature config value = } ( defs, bottomIn ) = - unnest { conf | state = newState } inVal + unnest { configWithLetDefsSoFar | state = newState } inVal in ( ( defName, viewValue config def.body ) :: defs, bottomIn ) - notLet -> - ( [], viewValue config notLet ) + notALetNode -> + ( [], viewValue configWithLetDefsSoFar notALetNode ) ( _, inValueElem ) = unnest config value @@ -338,8 +341,8 @@ viewValueByLanguageFeature config value = el [ Element.centerX, Element.centerY, smallPadding config.state.theme |> padding ] (text "not set") Value.UpdateRecord _ record newFields -> - Element.column [ Element.height fill ] - [ Element.row [ smallPadding config.state.theme |> padding ] [ text "updating ", viewValue config record, text " with" ] + Element.column [ Background.color config.state.theme.colors.lightest, Theme.borderRounded config.state.theme ] + [ Element.row [ smallPadding config.state.theme |> padding ] [ text "updating the following fields of ", viewValue config record] , ViewRecord.view config (viewValue config) newFields ] @@ -355,7 +358,7 @@ viewValueByLanguageFeature config value = Element.column [ Background.color (rgb 1 0.6 0.6) , smallPadding config.state.theme |> padding - , Border.rounded 6 + , Theme.borderRounded config.state.theme ] [ Element.el [ smallPadding config.state.theme |> padding @@ -365,7 +368,7 @@ viewValueByLanguageFeature config value = , Element.el [ Background.color (rgb 1 1 1) , smallPadding config.state.theme |> padding - , Border.rounded 6 + , Theme.borderRounded config.state.theme , width fill ] (XRayView.viewValue (XRayView.viewType moduleNameToPathString) ((other |> Debug.log "unable to visualize: ") |> Value.mapValueAttributes identity (\( _, tpe ) -> tpe))) diff --git a/tests-integration/decoration-model/elm.json b/tests-integration/decoration-model/elm.json new file mode 100644 index 000000000..ce2a08dc7 --- /dev/null +++ b/tests-integration/decoration-model/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/tests-integration/decoration-model/morphir.json b/tests-integration/decoration-model/morphir.json new file mode 100644 index 000000000..9d905e2ba --- /dev/null +++ b/tests-integration/decoration-model/morphir.json @@ -0,0 +1,4 @@ +{ + "name": "Morphir.Decoration.Model", + "sourceDirectory": "src" +} diff --git a/tests-integration/decoration-model/src/Morphir/Decoration/Model/Composites.elm b/tests-integration/decoration-model/src/Morphir/Decoration/Model/Composites.elm new file mode 100644 index 000000000..fbfccdb50 --- /dev/null +++ b/tests-integration/decoration-model/src/Morphir/Decoration/Model/Composites.elm @@ -0,0 +1,18 @@ +module Morphir.Decoration.Model.Composites exposing (..) + + +type alias SourceRecord = + { name : String + , sequenceNumber : Float + , details : String + } + + +type alias DatabaseName = + String + + +type Repositories + = Database DatabaseName + | FileSystem String + | Memory diff --git a/tests-integration/decoration-model/src/Morphir/Decoration/Model/Database.elm b/tests-integration/decoration-model/src/Morphir/Decoration/Model/Database.elm new file mode 100644 index 000000000..05ebb6ece --- /dev/null +++ b/tests-integration/decoration-model/src/Morphir/Decoration/Model/Database.elm @@ -0,0 +1,29 @@ +module Morphir.Decoration.Model.Database exposing (..) + + +type alias Entity = + Bool + + +type alias ColumnName = + String + + +type alias TableName = + String + + +type alias Table = + Table TableName + + +type Column + = Column ColumnName + + +type alias Id = + Bool + + +type alias GeneratedValue = + Bool diff --git a/tests-integration/decoration-model/src/Morphir/Decoration/Model/JsonSchema.elm b/tests-integration/decoration-model/src/Morphir/Decoration/Model/JsonSchema.elm new file mode 100644 index 000000000..dc3e2ae6c --- /dev/null +++ b/tests-integration/decoration-model/src/Morphir/Decoration/Model/JsonSchema.elm @@ -0,0 +1,91 @@ +module Morphir.Decoration.Model.JsonSchema exposing (..) + + +type alias SchemaEnabled = + Bool + + + +-- String Type Decorations + + +type alias MinLength = + Int + + +type alias MaxLength = + Int + + +type alias Pattern = + String + + +type Format + = DateTime + | Time + | Date + | Duration + | Email + | Hostname + | Uri + + + +-- number type decorations + + +type alias Minimum = + Int + + +type alias Maximum = + Int + + +type alias ExclusiveMinimum = + Int + + +type alias ExclusiveMaximum = + Int + + +type alias MultiplesOf = + Int + + + +-- Object Type Decorations + + +type alias MinProperties = + Int + + +type alias MaxProperties = + String + + + +-- Array Type Decorations + + +type alias MinContains = + Int + + +type alias MaxContains = + Int + + +type alias MinItems = + Int + + +type alias MaxItems = + Int + + +type alias Uniqueness = + Bool diff --git a/tests-integration/decoration-model/src/Morphir/Decoration/Model/NumberConstraints.elm b/tests-integration/decoration-model/src/Morphir/Decoration/Model/NumberConstraints.elm new file mode 100644 index 000000000..733563fa5 --- /dev/null +++ b/tests-integration/decoration-model/src/Morphir/Decoration/Model/NumberConstraints.elm @@ -0,0 +1,13 @@ +module Morphir.Decoration.Model.NumberConstraints exposing (..) + + +type alias Minimum = + Int + + +type alias Maximum = + Int + + +type alias Precision = + Int diff --git a/tests-integration/decoration-model/src/Morphir/Decoration/Model/PrivacyControl.elm b/tests-integration/decoration-model/src/Morphir/Decoration/Model/PrivacyControl.elm new file mode 100644 index 000000000..f7f2f3d96 --- /dev/null +++ b/tests-integration/decoration-model/src/Morphir/Decoration/Model/PrivacyControl.elm @@ -0,0 +1,14 @@ +module Morphir.Decoration.Model.PrivacyControl exposing (..) + +-- @docs Sensitivity + + +type Sensitivity + = MNPI + | PII + | PI + | SPI + | NPI + | Private_Information + | PHI + | RBC_High_Risk_Data diff --git a/tests-integration/decoration-model/src/Morphir/Decoration/Model/StringConstraints.elm b/tests-integration/decoration-model/src/Morphir/Decoration/Model/StringConstraints.elm new file mode 100644 index 000000000..415af4821 --- /dev/null +++ b/tests-integration/decoration-model/src/Morphir/Decoration/Model/StringConstraints.elm @@ -0,0 +1,9 @@ +module Morphir.Decoration.Model.StringConstraints exposing (..) + + +type alias MinLength = + Int + + +type alias MaxLength = + Int diff --git a/tests-integration/json-schema/model/src/TestModel/AdvancedTypes.elm b/tests-integration/json-schema/model/src/TestModel/AdvancedTypes.elm index 100317010..68366167e 100644 --- a/tests-integration/json-schema/model/src/TestModel/AdvancedTypes.elm +++ b/tests-integration/json-schema/model/src/TestModel/AdvancedTypes.elm @@ -1,9 +1,8 @@ module TestModel.AdvancedTypes exposing (..) import Morphir.SDK.Decimal exposing (..) -import Morphir.SDK.LocalDate exposing (LocalDate) +import Morphir.SDK.LocalDate exposing (LocalDate, Month) import Morphir.SDK.LocalTime exposing (LocalTime) -import Morphir.SDK.Month exposing (Month) import TestModel.BasicTypes exposing (..) diff --git a/tests-integration/json-schema/model/src/TestModel/CustomTypes.elm b/tests-integration/json-schema/model/src/TestModel/CustomTypes.elm index 612952a62..2860d5a40 100644 --- a/tests-integration/json-schema/model/src/TestModel/CustomTypes.elm +++ b/tests-integration/json-schema/model/src/TestModel/CustomTypes.elm @@ -1,7 +1,7 @@ module TestModel.CustomTypes exposing (..) import TestModel.AdvancedTypes exposing (Score) -import Morphir.SDK.Month exposing (Month) +import Morphir.SDK.LocalDate exposing (Month) type PersonalData diff --git a/tests-integration/reference-model/morphir-tests.json b/tests-integration/reference-model/morphir-tests.json index 27cc404ec..8a998ecfd 100644 --- a/tests-integration/reference-model/morphir-tests.json +++ b/tests-integration/reference-model/morphir-tests.json @@ -14,245 +14,52 @@ ], [ [ - "relational" + "s", + "d", + "k" + ], + [ + "dict" ] ], [ - "inner", - "join", - "1" + "map", + "users" ] ], [ - { - "inputs": [ - [], - [] - ], - "expectedOutput": [], - "description": "" - }, - { - "inputs": [ - [ - { - "companyName": "foo", - "position": "12w21w" - } - ], - [] - ], - "expectedOutput": [], - "description": "" - }, { "inputs": [ [ - { - "companyName": "foo", - "position": "12w21w" - } - ], - [ - { - "name": "foo", - "numberOfEmployees": 123 - } + [ + "car", + "work" + ] ] ], "expectedOutput": [ - { - "position": "12w21w", - "companySize": 123 - } - ], - "description": "" - }, - { - "inputs": [ [ - { - "companyName": "foo", - "position": "12w21w" - } - ], - [ - { - "name": "bar", - "numberOfEmployees": 123 - } + "car", + "carwork" ] ], - "expectedOutput": [], "description": "" }, { "inputs": [ [ - { - "companyName": "bar", - "position": "efewfwe" - }, - { - "companyName": "foo", - "position": "12w21w" - } - ], - [ - { - "name": "foo", - "numberOfEmployees": 123 - }, - { - "name": "bar", - "numberOfEmployees": 456 - } + [ + "2", + "elor" + ] ] ], "expectedOutput": [ - { - "position": "efewfwe", - "companySize": 456 - }, - { - "position": "12w21w", - "companySize": 123 - } - ], - "description": "" - } - ] - ], - [ - [ - [ - [ - "morphir" - ], - [ - "reference" - ], - [ - "model" - ] - ], - [ - [ - "relational" - ] - ], - [ - "left", - "join", - "1" - ] - ], - [ - { - "inputs": [ [ - { - "companyName": "foo", - "position": "wedfef" - } - ], - [] - ], - "expectedOutput": [ - { - "position": "wedfef", - "companySize": 0 - } - ], - "description": "" - }, - { - "inputs": [ - [ - { - "companyName": "foo", - "position": "wedfef" - } - ], - [ - { - "name": "foo", - "numberOfEmployees": 12312 - } + "2", + "2elor" ] ], - "expectedOutput": [ - { - "position": "wedfef", - "companySize": 12312 - } - ], - "description": "" - }, - { - "inputs": [ - [ - { - "companyName": "foo", - "position": "wedfef" - } - ], - [ - { - "name": "bar", - "numberOfEmployees": 12312 - } - ] - ], - "expectedOutput": [ - { - "position": "wedfef", - "companySize": 0 - } - ], - "description": "" - } - ] - ], - [ - [ - [ - [ - "morphir" - ], - [ - "reference" - ], - [ - "model" - ] - ], - [ - [ - "test", - "model" - ], - [ - "testing" - ] - ], - [ - "add", - "7" - ] - ], - [ - { - "inputs": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "expectedOutput": 28, "description": "" } ] diff --git a/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/Dict.elm b/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/Dict.elm index dd9daa7d9..08674b95c 100644 --- a/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/Dict.elm +++ b/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/Dict.elm @@ -3,52 +3,52 @@ module Morphir.Reference.Model.SDK.Dict exposing (..) import Dict exposing (Dict) -dictEmpty : Dict k v +dictEmpty : Dict String String dictEmpty = Dict.empty -dictSingleton : comparable -> b -> Dict comparable b +dictSingleton : String -> String -> Dict String String dictSingleton key value = Dict.singleton key value -dictIsEmpty : Dict k v -> Bool +dictIsEmpty : Dict String String -> Bool dictIsEmpty dictionary = Dict.isEmpty dictionary -dictRemove : comparable -> Dict comparable v -> Dict comparable v +dictRemove : String -> Dict String String -> Dict String String dictRemove key dict = Dict.remove key dict -dictMember : comparable -> Dict comparable v -> Bool +dictMember : String -> Dict String String -> Bool dictMember key dict = Dict.member key dict -dictSize : Dict k v -> Int +dictSize : Dict String String -> Int dictSize dict = Dict.size dict -dictKeys : Dict k v -> List k +dictKeys : Dict String String -> List String dictKeys dict = Dict.keys dict -dictValues : Dict k v -> List v +dictValues : Dict String String -> List String dictValues dict = Dict.values dict -dictToList : Dict k v -> List ( k, v ) +dictToList : Dict String String -> List ( String, String ) dictToList dict = Dict.toList dict -dictInsert : comparable -> b -> Dict comparable b -> Dict comparable b +dictInsert : String -> String -> Dict String String -> Dict String String dictInsert key value dict = Dict.insert key value dict @@ -61,3 +61,30 @@ initialUsers = updatedUsers : Dict number String updatedUsers = Dict.update 1 (Maybe.map (\name -> String.append name " Johnson")) initialUsers + + +mapUsers : Dict String String -> Dict String String +mapUsers dict = + Dict.map (\id name -> id ++ name) dict + + +type alias Person = + { name : String + , age : Int + } + + +dictFoldl : Dict String Person -> Int +dictFoldl dict = + Dict.foldl (\_ person acc -> acc + person.age) 0 dict + + + +--dictFoldr : Dict String Person -> List Int +--dictFoldr dict = +-- Dict.foldr (\_ person acc -> person.age :: acc) [] dict +-- +-- +--filter : Dict String Person -> Dict String Person +--filter dict = +-- Dict.filter (\name person -> name == person.name) dict diff --git a/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/LocalDate.elm b/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/LocalDate.elm index 93f6330f6..a899ee90a 100644 --- a/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/LocalDate.elm +++ b/tests-integration/reference-model/src/Morphir/Reference/Model/SDK/LocalDate.elm @@ -3,6 +3,16 @@ module Morphir.Reference.Model.SDK.LocalDate exposing (..) import Morphir.SDK.LocalDate as Date exposing (..) +day : LocalDate -> Int +day date = + Date.day date + + +dayOfWeek : LocalDate -> DayOfWeek +dayOfWeek date = + Date.dayOfWeek date + + diffInDays : LocalDate -> LocalDate -> Int diffInDays fromDate toDate = Date.diffInDays fromDate toDate @@ -57,6 +67,21 @@ addYears count date = Date.addYears count date +{-| Create a date from a [calendar date][gregorian]: a year, month, and day of +the month. Out-of-range day values will be clamped. + + import Morphir.SDK.LocalDate exposing (fromCalendarDate, Month(..)) + + fromCalendarDate 2018 September 26 + +[gregorian]: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar + +-} +fromCalendarDate : Int -> Month -> Int -> LocalDate +fromCalendarDate y m d = + Date.fromCalendarDate y m d + + {-| Construct a LocalDate based on ISO formatted string. Opportunity for error denoted by Maybe return type. -} fromISO : String -> Maybe LocalDate @@ -64,6 +89,20 @@ fromISO iso = Date.fromISO iso +{-| Returns true if the date falls on a weekend (Saturday or Sunday). +-} +isWeekend : LocalDate -> Bool +isWeekend date = + Date.isWeekend date + + +{-| Returns true if the date falls on a weekday (any day other than Saturday or Sunday). +-} +isWeekday : LocalDate -> Bool +isWeekday date = + Date.isWeekday date + + {-| Convert a LocalDate to a string in ISO format. -} toISOString : LocalDate -> String @@ -71,10 +110,45 @@ toISOString localDate = Date.toISOString localDate +{-| Create a date from an [ordinal date][ordinaldate]: a year and day of the +year. Out-of-range day values will be clamped. + + import Morphir.SDK.LocalDate exposing (fromOrdinalDate) + + fromOrdinalDate 2018 269 + +[ordinaldate]: https://en.wikipedia.org/wiki/Ordinal_date + +-} +fromOrdinalDate : Int -> Int -> LocalDate +fromOrdinalDate y dayOfYear = + Date.fromOrdinalDate y dayOfYear + + {-| Construct a LocalDate based on Year, Month, Day. Opportunity for error denoted by Maybe return type. Errors can occur when any of the given values fall outside of their relevant constraints. For example, the date given as 2000 2 30 (2000-Feb-30) would fail because the day of the 30th is impossible. -} fromParts : Int -> Int -> Int -> Maybe LocalDate -fromParts year month day = - Date.fromParts year month day +fromParts y m d = + Date.fromParts y m d + + +month : LocalDate -> Month +month date = + Date.month date + + +monthNumber : LocalDate -> Int +monthNumber date = + Date.monthNumber date + + +monthToInt : Month -> Int +monthToInt m = + Date.monthToInt m + + +year : LocalDate -> Int +year date = + Date.year date diff --git a/tests-integration/snowpark/model/elm.json b/tests-integration/snowpark/model/elm.json new file mode 100644 index 000000000..ce2a08dc7 --- /dev/null +++ b/tests-integration/snowpark/model/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/tests-integration/snowpark/model/morphir.json b/tests-integration/snowpark/model/morphir.json new file mode 100644 index 000000000..a4648f366 --- /dev/null +++ b/tests-integration/snowpark/model/morphir.json @@ -0,0 +1,12 @@ +{ + "name": "CompanyAssets", + "sourceDirectory": "src", + "decorations": { + "snowparkgendecorations": { + "displayName" : "Snowpark generation customization", + "entryPoint": "SnowparkGenCustomization:Decorations:GenerationCustomization", + "ir": "outsp/src/main/scala/decorations/morphir-ir.json", + "storageLocation": "spdecorations.json" + } + } +} diff --git a/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Assets.elm b/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Assets.elm new file mode 100644 index 000000000..d9f0a5b34 --- /dev/null +++ b/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Assets.elm @@ -0,0 +1,12 @@ +module CompanyAssets.DataDefinition.Assets exposing (..) +import CompanyAssets.DataDefinition.Types exposing (Price, AssetCategory, AssetSubCategory(..)) + +type alias Asset = + { assetId : Int + , name : String + , category : AssetCategory + , subcategory : Maybe AssetSubCategory + , price : Price + , purchaseYear : Int + , vendorId : Int + } diff --git a/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Types.elm b/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Types.elm new file mode 100644 index 000000000..4c8cc0aeb --- /dev/null +++ b/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Types.elm @@ -0,0 +1,24 @@ +module CompanyAssets.DataDefinition.Types exposing (Price, AssetCategory(..), AssetSubCategory(..), Year) + +type alias Price = Float + +type alias Year = Int + + +type AssetCategory = + Vehicle + | Furniture + | Building + | OfficeEquipment + + +type AssetSubCategory = + Car + | Boat + | Office + | Warehouse + | Truck + | Computer + | Printer + | Phone + | Rental \ No newline at end of file diff --git a/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Vendors.elm b/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Vendors.elm new file mode 100644 index 000000000..de8f94c1f --- /dev/null +++ b/tests-integration/snowpark/model/src/CompanyAssets/DataDefinition/Vendors.elm @@ -0,0 +1,7 @@ +module CompanyAssets.DataDefinition.Vendors exposing (..) + + +type alias Vendor = + { vendorId : Int + , description : String + } \ No newline at end of file diff --git a/tests-integration/snowpark/model/src/CompanyAssets/Rules/DepreciationRules.elm b/tests-integration/snowpark/model/src/CompanyAssets/Rules/DepreciationRules.elm new file mode 100644 index 000000000..8a9029de3 --- /dev/null +++ b/tests-integration/snowpark/model/src/CompanyAssets/Rules/DepreciationRules.elm @@ -0,0 +1,72 @@ +module CompanyAssets.Rules.DepreciationRules exposing (usefulLifeExceeded) + +import CompanyAssets.DataDefinition.Assets exposing (Asset) +import CompanyAssets.DataDefinition.Types exposing (AssetCategory(..), AssetSubCategory(..)) +import CompanyAssets.DataDefinition.Types exposing (Price, Year) + + +usefulLifeExceeded : Year -> List Asset -> List { category : String, price : Price } +usefulLifeExceeded currentYear assets = + assets + |> List.map + (\asset -> + { category = + if check_rental_property currentYear asset then + "rental property" + else if check_vessels currentYear asset then + "vessel" + else if check_office_equipment currentYear asset then + "office" + else if check_for_computer_equipment currentYear asset then + "computer" + else if check_for_cars currentYear asset then + "cars" + else + "" + , price = asset.price + } + ) + |> List.filter (\p -> p.category /= "") + +check_for_cars : Year -> Asset -> Bool +check_for_cars currentYear asset = + case (asset.category, asset.subcategory) of + (Vehicle, Just Car) -> (currentYear - asset.purchaseYear) >= 5 + (Vehicle, Just Truck) -> (currentYear - asset.purchaseYear) >= 5 + (_,_) -> False + +check_for_computer_equipment : Year -> Asset -> Bool +check_for_computer_equipment currentYear asset = + case (asset.category, asset.subcategory) of + (OfficeEquipment, Just Computer) -> (currentYear - asset.purchaseYear) >= 6 + (OfficeEquipment, Just Printer) -> (currentYear - asset.purchaseYear) >= 7 + _ -> False + + +check_office_equipment : Year -> Asset -> Bool +check_office_equipment currentYear asset = + case (asset.category, asset.subcategory) of + (OfficeEquipment, Just Phone) -> (currentYear - asset.purchaseYear) >= 6 + (Furniture, _) -> (currentYear - asset.purchaseYear) >= 7 + _ -> False + + +compare_maybe_value : Maybe a -> a -> Bool +compare_maybe_value maybeValue toCompare = + maybeValue + |> Maybe.map (\t -> t == toCompare) + |> Maybe.withDefault False + +check_vessels : Year -> Asset -> Bool +check_vessels currentYear asset = + compare_maybe_value asset.subcategory Boat + && currentYear - asset.purchaseYear >= 10 + + +check_rental_property : Year -> Asset -> Bool +check_rental_property currentYear asset = + asset.category == Building + && compare_maybe_value asset.subcategory Rental + && currentYear - asset.purchaseYear >= 27 + + \ No newline at end of file diff --git a/tests-integration/snowpark/scala/build.sc b/tests-integration/snowpark/scala/build.sc new file mode 100644 index 000000000..5768171c8 --- /dev/null +++ b/tests-integration/snowpark/scala/build.sc @@ -0,0 +1,21 @@ +// build.sc +import mill._ +import scalalib._ + + +object snowparkExample extends ScalaModule{ + def scalaVersion = "2.12.9" + + val paths = Seq( + millSourcePath / os.up / "src" / "main" / "scala" + ) + def sources = T.sources { + paths.map(p => PathRef(p)) + } + + def ivyDeps = Agg( + ivy"com.snowflake:snowpark:1.8.0", + ivy"org.ini4j:ini4j:0.5.4", + ivy"org.scala-lang.modules::scala-collection-compat:2.3.1" + ) +} diff --git a/tests-integration/snowpark/scala/mill b/tests-integration/snowpark/scala/mill new file mode 100755 index 000000000..93ef60438 --- /dev/null +++ b/tests-integration/snowpark/scala/mill @@ -0,0 +1,49 @@ +#!/usr/bin/env sh + +# This is a wrapper script, that automatically download mill from GitHub release pages +# You can give the required mill version with MILL_VERSION env variable +# If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +DEFAULT_MILL_VERSION=0.10.4 + +set -e + +if [ -z "$MILL_VERSION" ] ; then + if [ -f ".mill-version" ] ; then + MILL_VERSION="$(head -n 1 .mill-version 2> /dev/null)" + elif [ -f "mill" ] && [ "$0" != "mill" ] ; then + MILL_VERSION=$(grep -F "DEFAULT_MILL_VERSION=" "mill" | head -n 1 | cut -d= -f2) + else + MILL_VERSION=$DEFAULT_MILL_VERSION + fi +fi + +if [ "x${XDG_CACHE_HOME}" != "x" ] ; then + MILL_DOWNLOAD_PATH="${XDG_CACHE_HOME}/mill/download" +else + MILL_DOWNLOAD_PATH="${HOME}/.cache/mill/download" +fi +MILL_EXEC_PATH="${MILL_DOWNLOAD_PATH}/${MILL_VERSION}" + +version_remainder="$MILL_VERSION" +MILL_MAJOR_VERSION="${version_remainder%%.*}"; version_remainder="${version_remainder#*.}" +MILL_MINOR_VERSION="${version_remainder%%.*}"; version_remainder="${version_remainder#*.}" + +if [ ! -s "$MILL_EXEC_PATH" ] ; then + mkdir -p "$MILL_DOWNLOAD_PATH" + if [ "$MILL_MAJOR_VERSION" -gt 0 ] || [ "$MILL_MINOR_VERSION" -ge 5 ] ; then + ASSEMBLY="-assembly" + fi + DOWNLOAD_FILE=$MILL_EXEC_PATH-tmp-download + MILL_VERSION_TAG=$(echo $MILL_VERSION | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') + MILL_DOWNLOAD_URL="https://github.com/lihaoyi/mill/releases/download/${MILL_VERSION_TAG}/$MILL_VERSION${ASSEMBLY}" + curl --fail -L -o "$DOWNLOAD_FILE" "$MILL_DOWNLOAD_URL" + chmod +x "$DOWNLOAD_FILE" + mv "$DOWNLOAD_FILE" "$MILL_EXEC_PATH" + unset DOWNLOAD_FILE + unset MILL_DOWNLOAD_URL +fi + +unset MILL_DOWNLOAD_PATH +unset MILL_VERSION + +exec $MILL_EXEC_PATH "$@" \ No newline at end of file diff --git a/tests-integration/snowpark/scala/mill.bat b/tests-integration/snowpark/scala/mill.bat new file mode 100644 index 000000000..16fe05668 --- /dev/null +++ b/tests-integration/snowpark/scala/mill.bat @@ -0,0 +1,95 @@ +@echo off + +rem This is a wrapper script, that automatically download mill from GitHub release pages +rem You can give the required mill version with --mill-version parameter +rem If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +rem +rem Project page: https://github.com/lefou/millw +rem +rem If you want to improve this script, please also contribute your changes back! +rem +rem Licensed under the Apache License, Version 2.0 + +rem setlocal seems to be unavailable on Windows 95/98/ME +rem but I don't think we need to support them in 2019 +setlocal enabledelayedexpansion + +set "DEFAULT_MILL_VERSION=0.7.3" + +rem %~1% removes surrounding quotes +if [%~1%]==[--mill-version] ( + rem shift command doesn't work within parentheses + if not [%~2%]==[] ( + set MILL_VERSION=%~2% + set "STRIP_VERSION_PARAMS=true" + ) else ( + echo You specified --mill-version without a version. + echo Please provide a version that matches one provided on + echo https://github.com/lihaoyi/mill/releases + exit /b 1 + ) +) + +if [!MILL_VERSION!]==[] ( + if exist .mill-version ( + set /p MILL_VERSION=<.mill-version + ) +) + +if [!MILL_VERSION!]==[] ( + set MILL_VERSION=%DEFAULT_MILL_VERSION% +) + +set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download + +rem without bat file extension, cmd doesn't seem to be able to run it +set MILL=%MILL_DOWNLOAD_PATH%\!MILL_VERSION!.bat + +if not exist "%MILL%" ( + set VERSION_PREFIX=%MILL_VERSION:~0,4% + set DOWNLOAD_SUFFIX=-assembly + if [!VERSION_PREFIX!]==[0.0.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.1.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.2.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.3.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.4.] set DOWNLOAD_SUFFIX= + set VERSION_PREFIX= + + rem there seems to be no way to generate a unique temporary file path (on native Windows) + set DOWNLOAD_FILE=%MILL%.tmp + + echo Downloading mill %MILL_VERSION% from https://github.com/lihaoyi/mill/releases ... + + rem curl is bundled with recent Windows 10 + rem but I don't think we can expect all the users to have it in 2019 + rem bitadmin seems to be available on Windows 7 + rem without /dynamic, github returns 403 + rem bitadmin is sometimes needlessly slow but it looks better with /priority foreground + if not exist "%MILL_DOWNLOAD_PATH%" mkdir "%MILL_DOWNLOAD_PATH%" + bitsadmin /transfer millDownloadJob /dynamic /priority foreground "https://github.com/lihaoyi/mill/releases/download/%MILL_VERSION%/%MILL_VERSION%!DOWNLOAD_SUFFIX!" "!DOWNLOAD_FILE!" + if not exist "!DOWNLOAD_FILE!" ( + echo Could not download mill %MILL_VERSION% + exit 1 + ) + + move /y "!DOWNLOAD_FILE!" "%MILL%" + + set DOWNLOAD_FILE= + set DOWNLOAD_SUFFIX= +) + +set MILL_DOWNLOAD_PATH= +set MILL_VERSION= + +set MILL_PARAMS=%* + +if defined STRIP_VERSION_PARAMS ( + for /f "tokens=1-2*" %%a in ("%*") do ( + rem strip %%a - It's the "--mill-version" option. + rem strip %%b - it's the version number that comes after the option. + rem keep %%c - It's the remaining options. + set MILL_PARAMS=%%c + ) +) + +"%MILL%" -i %MILL_PARAMS% \ No newline at end of file diff --git a/tests-integration/snowpark/scala/src/main/scala/entrypoint/Program.scala b/tests-integration/snowpark/scala/src/main/scala/entrypoint/Program.scala new file mode 100644 index 000000000..b36037eeb --- /dev/null +++ b/tests-integration/snowpark/scala/src/main/scala/entrypoint/Program.scala @@ -0,0 +1,17 @@ +package entryPoint; + +import com.snowflake.snowpark._ +import com.snowflake.snowpark.functions._ + +object Program extends App { + println("Snowpark test program"); + implicit val session = Session.builder.configFile("session.properties").create + + val assets = session.table("EXAMPLE_ASSETS"); + + companyassets.rules.DepreciationRules.usefulLifeExceeded(lit(2023))(assets).show + + session.close() +} + + diff --git a/tests-integration/typespec/model/elm.json b/tests-integration/typespec/model/elm.json index 34ad48160..f8de0f201 100644 --- a/tests-integration/typespec/model/elm.json +++ b/tests-integration/typespec/model/elm.json @@ -9,11 +9,11 @@ "direct": { "elm/browser": "1.0.2", "elm/core": "1.0.5", + "elm/time": "1.0.0", "elm/html": "1.0.0" }, "indirect": { "elm/json": "1.1.3", - "elm/time": "1.0.0", "elm/url": "1.0.0", "elm/virtual-dom": "1.0.3" } diff --git a/tests-integration/typespec/model/src/TestModel/AdvancedTypes.elm b/tests-integration/typespec/model/src/TestModel/AdvancedTypes.elm index c742c8de3..13223efb2 100644 --- a/tests-integration/typespec/model/src/TestModel/AdvancedTypes.elm +++ b/tests-integration/typespec/model/src/TestModel/AdvancedTypes.elm @@ -1,9 +1,8 @@ module TestModel.AdvancedTypes exposing (..) import Morphir.SDK.Decimal exposing (Decimal) -import Morphir.SDK.LocalDate exposing (LocalDate) +import Morphir.SDK.LocalDate exposing (LocalDate, Month) import Morphir.SDK.LocalTime exposing (LocalTime) -import Morphir.SDK.Month exposing (Month) type alias Price = diff --git a/tests/Morphir/SDK/LocalDateTests.elm b/tests/Morphir/SDK/LocalDateTests.elm index 220c37fd0..579dd1d60 100644 --- a/tests/Morphir/SDK/LocalDateTests.elm +++ b/tests/Morphir/SDK/LocalDateTests.elm @@ -96,4 +96,16 @@ constructorTests = \_ -> LocalDate.fromParts 2020 2 30 |> Expect.equal Nothing + , test "valid fromCalendarDate" <| + \_ -> + LocalDate.fromCalendarDate 2023 December 25 + |> Expect.equal (Date.fromCalendarDate 2023 Dec 25) + , test "invalid but pinned fromCalendarDate" <| + \_ -> + LocalDate.fromCalendarDate 2023 December 39 + |> Expect.equal (Date.fromCalendarDate 2023 Dec 31) + , test "valid fromOrdinalDate" <| + \_ -> + LocalDate.fromOrdinalDate 2023 15 + |> Expect.equal (Date.fromCalendarDate 2023 Jan 15) ] diff --git a/tests/Morphir/Snowpark/AccessElementTests.elm b/tests/Morphir/Snowpark/AccessElementTests.elm new file mode 100644 index 000000000..9708c2cbe --- /dev/null +++ b/tests/Morphir/Snowpark/AccessElementTests.elm @@ -0,0 +1,92 @@ +module Morphir.Snowpark.AccessElementTests exposing (mapFieldAccessTests) + +import Dict exposing (Dict(..)) +import Expect +import Morphir.IR.FQName as FQName +import Morphir.IR.Name as Name +import Morphir.IR.Type as Type +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( testDistributionName + , testDistributionPackage + ) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext as MappingContext exposing (emptyValueMappingContext) +import Set +import Test exposing (Test, describe, test) + + +stringReference : Type.Type () +stringReference = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "boolean" ] ) [] + + +recordFieldAccess : Value.Value () (Type.Type ()) +recordFieldAccess = + Value.Field + stringReference + (Value.Variable + (Type.Reference () (FQName.fromString "UTest:MyMod:Emp" ":") []) + (Name.fromString "x") + ) + (Name.fromString "salary") + + +referenceToDefinition : Value.Value () (Type.Type ()) +referenceToDefinition = + Value.Reference stringReference (FQName.fromString "ATest:AMod:counter" ":") + + +constructorReference : Value.Value () (Type.Type ()) +constructorReference = + Value.Constructor + (Type.Reference () (FQName.fromString "UTest:MyMod:DeptKind" ":") []) + (FQName.fromString "UTest:MyMod:Hr" ":") + + +mapFieldAccessTests : Test +mapFieldAccessTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( calculatedContext, _, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + valueMapContext = + { emptyValueMappingContext | typesContextInfo = calculatedContext } + + assertMapFieldAccess = + test "Convert record field reference" <| + \_ -> + let + ( mapped, _ ) = + mapValue recordFieldAccess valueMapContext + in + Expect.equal (Scala.Ref [ "utest", "MyMod", "Emp" ] "salary") mapped + + assertMapExternalDefinitionReference = + test "Convert definition reference" <| + \_ -> + let + ( mapped, _ ) = + mapValue referenceToDefinition valueMapContext + in + Expect.equal (Scala.Ref [ "atest", "AMod" ] "counter") mapped + + assertMapConstructorReference = + test "Convert constructor reference" <| + \_ -> + let + ( mapped, _ ) = + mapValue constructorReference valueMapContext + in + Expect.equal (Scala.Ref [ "utest", "MyMod", "DeptKind" ] "Hr") mapped + in + describe "AccessElementsTests" + [ assertMapFieldAccess + , assertMapExternalDefinitionReference + , assertMapConstructorReference + ] diff --git a/tests/Morphir/Snowpark/AggregateTests.elm b/tests/Morphir/Snowpark/AggregateTests.elm new file mode 100644 index 000000000..35befc4c6 --- /dev/null +++ b/tests/Morphir/Snowpark/AggregateTests.elm @@ -0,0 +1,159 @@ +module Morphir.Snowpark.AggregateTests exposing (..) + +import Dict +import Expect +import Morphir.IR.FQName as FQName +import Morphir.IR.Path as Path +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( aggregateFunction + , aggregateTypeInstance + , employeeInfo + , floatTypeInstance + , groupByFunction + , key0Type + , mFieldFunction + , mFuncTypeOf + , mIdOf + , mLambdaOf + , mListTypeOf + , sCall + , sLit + , sVar + , stringTypeInstance + , testDistributionName + , testDistributionPackage + ) +import Morphir.Snowpark.Constants exposing (applySnowparkFunc) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext as MappingContext exposing (emptyValueMappingContext) +import Morphir.Snowpark.ReferenceUtils exposing (curryCall) +import Set +import Test exposing (Test, describe, test) + + +groupBySection : Value.TypedValue +groupBySection = + curryCall + ( groupByFunction stringTypeInstance employeeInfo + , [ mFieldFunction stringTypeInstance [ "employee" ], mIdOf [ "employees" ] (mListTypeOf employeeInfo) ] + ) + + +aggregateSection : Value.TypedValue +aggregateSection = + curryCall + ( aggregateFunction stringTypeInstance employeeInfo floatTypeInstance + , [ aggregateLambda, groupBySection ] + ) + + +aggregateLambda : Value.TypedValue +aggregateLambda = + mLambdaOf ( [ "key" ], stringTypeInstance ) secondParamLambda + + +secondParamLambda : Value.TypedValue +secondParamLambda = + let + balanceType = + mFuncTypeOf + (aggregateTypeInstance [ "aggregation" ] [ employeeInfo, stringTypeInstance ]) + floatTypeInstance + + applyMinimum = + Value.Apply + (aggregateTypeInstance + [ "aggregation" ] + [ employeeInfo + , key0Type + ] + ) + (Value.Reference + (mFuncTypeOf + (mFuncTypeOf employeeInfo floatTypeInstance) + (aggregateTypeInstance [ "aggregation" ] [ employeeInfo, key0Type ]) + ) + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], [ "minimum", "of" ] ) + ) + (mFieldFunction (mFuncTypeOf employeeInfo floatTypeInstance) [ "min", "salary" ]) + + apply1LambdaBody = + Value.Apply + (mFuncTypeOf floatTypeInstance employeeInfo) + (Value.Constructor + (mFuncTypeOf stringTypeInstance (mFuncTypeOf floatTypeInstance employeeInfo)) + ( [ [ "deparments" ] ], [ [ "empleados" ] ], [ "employee", "info" ] ) + ) + (mIdOf [ "key" ] stringTypeInstance) + + apply2LambdaBody = + Value.Apply + floatTypeInstance + (mIdOf [ "balances" ] balanceType) + applyMinimum + + lambdaBody = + Value.Apply + employeeInfo + apply1LambdaBody + apply2LambdaBody + in + mLambdaOf ( [ "balances" ], balanceType ) lambdaBody + + +expectedResult : Scala.Value +expectedResult = + let + groupByObj = + sCall ( sVar "employees", "groupBy" ) [ sLit "employee" ] + + aggregateObj = + sCall + ( groupByObj, "agg" ) + [ sCall ( applySnowparkFunc "min" [ applySnowparkFunc "col" [ sLit "minSalary" ] ], "alias" ) [ sLit "minSalary" ] ] + in + sCall + ( aggregateObj, "select" ) + [ applySnowparkFunc "col" [ sLit "employee" ] + , applySnowparkFunc "col" [ sLit "minSalary" ] + ] + + +aggregateTests : Test +aggregateTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( calculatedContext, _, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + columnsObjects = + Dict.fromList + [ ( FQName.fromString "UTest:MyMod:TypeA" ":", "typeAColumns" ) + , ( FQName.fromString "UTest:MyMod:TypeB" ":", "typeBColumns" ) + , ( FQName.fromString "UTest:MyMod:TypeC" ":", "typeCColumns" ) + ] + + ctx = + { emptyValueMappingContext + | typesContextInfo = calculatedContext + , packagePath = Path.fromString "UTest" + , dataFrameColumnsObjects = columnsObjects + } + + assertAggregateTest = + test "Simple aggregate" <| + \_ -> + let + ( mapped, _ ) = + mapValue aggregateSection ctx + in + Expect.equal mapped expectedResult + in + describe "Aggregate test" + [ assertAggregateTest + ] diff --git a/tests/Morphir/Snowpark/CommonTestUtils.elm b/tests/Morphir/Snowpark/CommonTestUtils.elm new file mode 100644 index 000000000..f820a4c9d --- /dev/null +++ b/tests/Morphir/Snowpark/CommonTestUtils.elm @@ -0,0 +1,519 @@ +module Morphir.Snowpark.CommonTestUtils exposing (..) + +import Dict exposing (Dict(..)) +import Morphir.IR.AccessControlled exposing (public) +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal as Literal +import Morphir.IR.Module exposing (emptyDefinition) +import Morphir.IR.Name as Name +import Morphir.IR.Path as Path +import Morphir.IR.Type as Type +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.MapFunctionsMapping + exposing + ( basicsFunctionName + , dictFunctionName + , listFunctionName + , maybeFunctionName + ) + + +morphirNamespace : List (List String) +morphirNamespace = + [ [ "morphir" ], [ "s", "d", "k" ] ] + + +stringTypeInstance : Type.Type () +stringTypeInstance = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) [] + + +boolTypeInstance : Type.Type () +boolTypeInstance = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "bool" ] ) [] + + +intTypeInstance : Type.Type () +intTypeInstance = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) [] + + +floatTypeInstance : Type.Type () +floatTypeInstance = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) [] + + +aggregateTypeInstance : Name.Name -> List (Type.Type ()) -> Type.Type () +aggregateTypeInstance name args = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], name ) args + + +testDistributionName : Path.Path +testDistributionName = + Path.fromString "UTest" + + +typesDict = + Dict.fromList + [ ( Name.fromString "Emp" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "firstname", tpe = stringTypeInstance } + , { name = Name.fromString "lastname", tpe = stringTypeInstance } + ] + ) + } + ) + , ( Name.fromString "EmployeeInfo" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "employee", tpe = stringTypeInstance } + , { name = Name.fromString "minSalary", tpe = floatTypeInstance } + ] + ) + } + ) + , ( Name.fromString "TypeA" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "id", tpe = intTypeInstance } + ] + ) + } + ) + , ( Name.fromString "TypeB" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "id", tpe = intTypeInstance } + ] + ) + } + ) + , ( Name.fromString "TypeC" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "id", tpe = intTypeInstance } + ] + ) + } + ) + , ( Name.fromString "DeptKind" + , public + { doc = "" + , value = + Type.CustomTypeDefinition [] + (public + (Dict.fromList + [ ( Name.fromString "Hr", [] ) + , ( Name.fromString "It", [] ) + , ( Name.fromString "Logic", [] ) + ] + ) + ) + } + ) + , ( Name.fromString "TimeRange" + , public + { doc = "" + , value = + Type.CustomTypeDefinition [] + (public + (Dict.fromList + [ ( Name.fromString "Zero", [] ) + , ( Name.fromString "Seconds", [ ( [ "a1" ], intTypeInstance ) ] ) + , ( Name.fromString "MinutesAndSeconds", [ ( [ "a1" ], intTypeInstance ), ( [ "a2" ], intTypeInstance ) ] ) + ] + ) + ) + } + ) + ] + + +testDistributionPackage = + { modules = + Dict.fromList + [ ( Path.fromString "MyMod" + , public { emptyDefinition | types = typesDict } + ) + ] + } + + +mStringLiteralOf : String -> Value.TypedValue +mStringLiteralOf value = + Value.Literal stringTypeInstance (Literal.StringLiteral value) + + +mIntLiteralOf : Int -> Value.TypedValue +mIntLiteralOf value = + Value.Literal intTypeInstance (Literal.WholeNumberLiteral value) + + +mFloatLiteralOf : Float -> Value.TypedValue +mFloatLiteralOf value = + Value.Literal floatTypeInstance (Literal.FloatLiteral value) + + +mListTypeOf : Type.Type () -> Type.Type () +mListTypeOf tpe = + Type.Reference () (listFunctionName [ "list" ]) [ tpe ] + + +mDictTypeOf : Type.Type () -> Type.Type () -> Type.Type () +mDictTypeOf key value = + Type.Reference () (dictFunctionName [ "dict" ]) [ key, value ] + + +mFuncTypeOf : Type.Type () -> Type.Type () -> Type.Type () +mFuncTypeOf from to = + Type.Function () from to + + +mRecordTypeOf : List ( String, Type.Type () ) -> Type.Type () +mRecordTypeOf fields = + Type.Record () (List.map (\( name, tpe ) -> { name = [ name ], tpe = tpe }) fields) + + +mRecordOf : List ( String, Value.TypedValue ) -> Value.TypedValue +mRecordOf fields = + Value.Record + (mRecordTypeOf (List.map (\( name, val ) -> ( name, Value.valueAttribute val )) fields)) + (fields + |> List.map (\( name, val ) -> ( [ name ], val )) + |> Dict.fromList + ) + + +listConcatMapFunction : Type.Type () -> Type.Type () -> Value.TypedValue +listConcatMapFunction collectionFrom collectionTo = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf collectionFrom (mListTypeOf collectionTo)) + (mFuncTypeOf (mListTypeOf collectionFrom) (mListTypeOf collectionTo)) + ) + (listFunctionName [ "concat", "map" ]) + + +listFilterMapFunction : Type.Type () -> Type.Type () -> Value.TypedValue +listFilterMapFunction collectionFrom collectionTo = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf collectionFrom (mMaybeTypeOf collectionTo)) + (mFuncTypeOf (mListTypeOf collectionFrom) (mListTypeOf collectionTo)) + ) + (listFunctionName [ "filter", "map" ]) + + +equalFunction : Type.Type () -> Value.TypedValue +equalFunction tpe = + Value.Reference + (mFuncTypeOf tpe (mFuncTypeOf tpe boolTypeInstance)) + (basicsFunctionName [ "equal" ]) + + +addFunction : Type.Type () -> Value.TypedValue +addFunction tpe = + Value.Reference + (mFuncTypeOf tpe (mFuncTypeOf tpe tpe)) + (basicsFunctionName [ "add" ]) + + +listMapFunction : Type.Type () -> Type.Type () -> Value.TypedValue +listMapFunction collectionFrom collectionTo = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf collectionFrom collectionTo) + (mFuncTypeOf (mListTypeOf collectionFrom) (mListTypeOf collectionTo)) + ) + (listFunctionName [ "map" ]) + + +groupByFunction : Type.Type () -> Type.Type () -> Value.TypedValue +groupByFunction key a = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf a key) + (mFuncTypeOf (mListTypeOf a) (mDictTypeOf key (mListTypeOf a))) + ) + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], [ "group", "by" ] ) + + +aggregateFunction : Type.Type () -> Type.Type () -> Type.Type () -> Value.TypedValue +aggregateFunction key a b = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf key (mFuncTypeOf (aggregatorType a key0Type) b)) + (mFuncTypeOf (mDictTypeOf key (mListTypeOf a)) (mListTypeOf b)) + ) + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "aggregate" ] ], [ "aggregate" ] ) + + +aggregatorType : Type.Type () -> Type.Type () -> Type.Type () +aggregatorType a key = + aggregateTypeInstance [ "aggregator" ] [ a, key ] + + +key0Type : Type.Type () +key0Type = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "key" ] ], [ "key", "0" ] ) [] + + +listFilterFunction : Type.Type () -> Type.Type () -> Value.TypedValue +listFilterFunction collectionFrom collectionTo = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf collectionFrom boolTypeInstance) + (mFuncTypeOf (mListTypeOf collectionFrom) (mListTypeOf collectionTo)) + ) + (listFunctionName [ "filter" ]) + + +listConcatFunction : Type.Type () -> Value.TypedValue +listConcatFunction collectionElementType = + Value.Reference + (mFuncTypeOf + (mListTypeOf (mListTypeOf collectionElementType)) + (mListTypeOf collectionElementType) + ) + (listFunctionName [ "concat" ]) + + +listSumFunction : Type.Type () -> Value.TypedValue +listSumFunction collectionElementType = + Value.Reference + (mFuncTypeOf + (mListTypeOf collectionElementType) + collectionElementType + ) + (listFunctionName [ "sum" ]) + + +maybeMapFunction : Type.Type () -> Type.Type () -> Value.TypedValue +maybeMapFunction innerType targetType = + Value.Reference + (mFuncTypeOf + (mFuncTypeOf innerType targetType) + (mFuncTypeOf + (mMaybeTypeOf innerType) + (mMaybeTypeOf targetType) + ) + ) + (maybeFunctionName [ "map" ]) + + +maybeWithDefaultFunction : Type.Type () -> Value.TypedValue +maybeWithDefaultFunction innerType = + Value.Reference + (mFuncTypeOf + innerType + (mMaybeTypeOf innerType) + ) + (maybeFunctionName [ "with", "default" ]) + + +mLambdaOf : ( Name.Name, Type.Type () ) -> Value.TypedValue -> Value.TypedValue +mLambdaOf ( name, tpe ) body = + Value.Lambda + (mFuncTypeOf tpe (Value.valueAttribute body)) + (Value.AsPattern tpe (Value.WildcardPattern tpe) name) + body + + +mListOf : List Value.TypedValue -> Value.TypedValue +mListOf values = + let + tpe = + values + |> List.head + |> Maybe.map (\e -> Value.valueAttribute e) + |> Maybe.withDefault (Type.Unit ()) + in + Value.List (mListTypeOf tpe) values + + +mReferenceType : FQName.FQName -> List (Type.Type ()) -> Type.Type () +mReferenceType name list = + Type.Reference () name list + + +mLetOf : Name.Name -> Value.TypedValue -> Value.TypedValue -> Value.TypedValue +mLetOf name localValue body = + Value.LetDefinition + (Value.valueAttribute body) + name + { inputTypes = [] + , outputType = Value.valueAttribute localValue + , body = localValue + } + body + + +mMaybeTypeOf : Type.Type () -> Type.Type () +mMaybeTypeOf tpe = + Type.Reference () (maybeFunctionName [ "maybe" ]) [ tpe ] + + +empType = + Type.Reference () (FQName.fromString "UTest:MyMod:Emp" ":") [] + + +employeeInfo = + Type.Reference () (FQName.fromString "UTest:MyMod:EmployeeInfo" ":") [] + + +typeA = + Type.Reference () (FQName.fromString "UTest:MyMod:TypeA" ":") [] + + +typeB = + Type.Reference () (FQName.fromString "UTest:MyMod:TypeB" ":") [] + + +typeC = + Type.Reference () (FQName.fromString "UTest:MyMod:TypeC" ":") [] + + +mIdOf : Name.Name -> Type.Type () -> Value.TypedValue +mIdOf name tpe = + Value.Variable tpe name + + +sCall : ( Scala.Value, String ) -> List Scala.Value -> Scala.Value +sCall ( obj, memberName ) args = + Scala.Apply (Scala.Select obj memberName) (List.map (\arg -> Scala.ArgValue Nothing arg) args) + + +sExpCall : Scala.Value -> List Scala.Value -> Scala.Value +sExpCall exp args = + Scala.Apply exp (List.map (\arg -> Scala.ArgValue Nothing arg) args) + + +sVar : String -> Scala.Value +sVar name = + Scala.Variable name + + +sDot : Scala.Value -> String -> Scala.Value +sDot expr memberName = + Scala.Select expr memberName + + +sSnowparkRefFuncion : String -> Scala.Value +sSnowparkRefFuncion name = + Scala.Ref [ "com", "snowflake", "snowpark", "functions" ] name + + +sLit : String -> Scala.Value +sLit stringLit = + Scala.Literal (Scala.StringLit stringLit) + + +sIntLit : Int -> Scala.Value +sIntLit intLiteral = + Scala.Literal (Scala.IntegerLit intLiteral) + + +sFloatLit : Float -> Scala.Value +sFloatLit floatLiteral = + Scala.Literal (Scala.FloatLit floatLiteral) + + +sTrue : Scala.Value +sTrue = + Scala.Literal (Scala.BooleanLit True) + + +sFalse : Scala.Value +sFalse = + Scala.Literal (Scala.BooleanLit False) + + +sSpEqual : Scala.Value -> Scala.Value -> Scala.Value +sSpEqual left right = + Scala.BinOp left "===" right + + +sBlock : Scala.Value -> List ( Scala.Name, Scala.Value ) -> Scala.Value +sBlock body bindings = + let + valDecls = + bindings + |> List.map + (\( name, value ) -> + Scala.ValueDecl + { modifiers = [] + , pattern = Scala.NamedMatch name + , valueType = Nothing + , value = value + } + ) + in + Scala.Block valDecls body + + +innerJoinFunction : Type.Type () -> Type.Type () -> Value.TypedValue +innerJoinFunction collectionA collectionB = + Value.Reference + (mFuncTypeOf + (mListTypeOf collectionB) + (mFuncTypeOf + (mFuncTypeOf collectionA + (mFuncTypeOf collectionB boolTypeInstance) + ) + (mFuncTypeOf + (mListTypeOf collectionA) + (mListTypeOf (mTuple2TypeOf collectionA collectionB)) + ) + ) + ) + (listFunctionName [ "inner", "join" ]) + + +leftJoinFunction : Type.Type () -> Type.Type () -> Value.TypedValue +leftJoinFunction collectionA collectionB = + Value.Reference + (mFuncTypeOf + (mListTypeOf collectionB) + (mFuncTypeOf + (mFuncTypeOf collectionA + (mFuncTypeOf collectionB boolTypeInstance) + ) + (mFuncTypeOf + (mListTypeOf collectionA) + (mListTypeOf (mTuple2TypeOf collectionA (mMaybeTypeOf collectionB))) + ) + ) + ) + (listFunctionName [ "left", "join" ]) + + +mTuple2TypeOf : Type.Type () -> Type.Type () -> Type.Type () +mTuple2TypeOf tpe1 tpe2 = + Type.Tuple () [ tpe1, tpe2 ] + + +mField : Type.Type () -> Value.TypedValue -> String -> Value.TypedValue +mField tpe value name = + Value.Field tpe value [ name ] + + +mFieldFunction : Type.Type () -> Name.Name -> Value.TypedValue +mFieldFunction a name = + Value.FieldFunction a name diff --git a/tests/Morphir/Snowpark/FunctionGenerationTests.elm b/tests/Morphir/Snowpark/FunctionGenerationTests.elm new file mode 100644 index 000000000..5fe17283e --- /dev/null +++ b/tests/Morphir/Snowpark/FunctionGenerationTests.elm @@ -0,0 +1,115 @@ +module Morphir.Snowpark.FunctionGenerationTests exposing (functionGenTests) + +import Dict exposing (Dict(..)) +import Expect +import Morphir.IR.AccessControlled exposing (public) +import Morphir.IR.FQName as FQName +import Morphir.IR.Name as Name +import Morphir.IR.Path as Path +import Morphir.IR.Type as Type +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.Backend exposing (mapFunctionDefinition) +import Morphir.Snowpark.CommonTestUtils + exposing + ( stringTypeInstance + , testDistributionName + , testDistributionPackage + ) +import Morphir.Snowpark.Constants exposing (typeRefForSnowparkType) +import Morphir.Snowpark.MappingContext as MappingContext +import Set +import Test exposing (Test, describe, test) + + +functionGenTests : Test +functionGenTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + calculatedContext = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + typeOfRecord = + Type.Reference () (FQName.fromString "UTest:MyMod:Emp" ":") [] + + expectedFunctionBody = + Scala.Variable "x" + + assertGenerationOfBasicFunction = + test "Generate function definition" <| + \_ -> + let + functionDefinition = + public + { doc = "" + , value = + { inputTypes = + [ ( Name.fromString "a", typeOfRecord, typeOfRecord ) + , ( Name.fromString "b", stringTypeInstance, stringTypeInstance ) + ] + , outputType = stringTypeInstance + , body = Value.Variable stringTypeInstance (Name.fromString "x") + } + } + + ( mappedFunctionDefinition, _ ) = + mapFunctionDefinition (Name.fromString "foo") functionDefinition (Path.fromString "UTest") (Path.fromString "MyMod") calculatedContext + + expectedFunctionDeclaration = + Scala.FunctionDecl + { modifiers = [] + , name = "foo" + , typeArgs = [] + , args = + [ [ Scala.ArgDecl [] (Scala.TypeRef [ "utest", "MyMod" ] "Emp") "a" Nothing ] + , [ Scala.ArgDecl [] (typeRefForSnowparkType "Column") "b" Nothing ] + , [ Scala.ArgDecl [ Scala.Implicit ] (typeRefForSnowparkType "Session") "sfSession" Nothing ] + ] + , returnType = Just <| typeRefForSnowparkType "Column" + , body = Just expectedFunctionBody + } + in + Expect.equal expectedFunctionDeclaration mappedFunctionDefinition + + assertGenerationOfFunctionReturningRecord = + test "Generate function definition returnting record" <| + \_ -> + let + functionDefinitionReturningRec = + public + { doc = "" + , value = + { inputTypes = + [ ( Name.fromString "a", typeOfRecord, typeOfRecord ) + , ( Name.fromString "b", stringTypeInstance, stringTypeInstance ) + ] + , outputType = typeOfRecord + , body = Value.Variable stringTypeInstance (Name.fromString "x") + } + } + + ( mappedFunctionDefinitionReturningRec, _ ) = + mapFunctionDefinition (Name.fromString "goo") functionDefinitionReturningRec (Path.fromString "UTest") (Path.fromString "MyMod") calculatedContext + + expectedFunctionDeclarationRec = + Scala.FunctionDecl + { modifiers = [] + , name = "goo" + , typeArgs = [] + , args = + [ [ Scala.ArgDecl [] (Scala.TypeRef [ "utest", "MyMod" ] "Emp") "a" Nothing ] + , [ Scala.ArgDecl [] (typeRefForSnowparkType "Column") "b" Nothing ] + , [ Scala.ArgDecl [ Scala.Implicit ] (typeRefForSnowparkType "Session") "sfSession" Nothing ] + ] + , returnType = Just <| typeRefForSnowparkType "Column" + , body = Just expectedFunctionBody + } + in + Expect.equal expectedFunctionDeclarationRec mappedFunctionDefinitionReturningRec + in + describe "FunctionGenerationTests" + [ assertGenerationOfBasicFunction + , assertGenerationOfFunctionReturningRecord + ] diff --git a/tests/Morphir/Snowpark/FunctionMappingsTests.elm b/tests/Morphir/Snowpark/FunctionMappingsTests.elm new file mode 100644 index 000000000..67edc53d1 --- /dev/null +++ b/tests/Morphir/Snowpark/FunctionMappingsTests.elm @@ -0,0 +1,926 @@ +module Morphir.Snowpark.FunctionMappingsTests exposing (functionMappingsTests) + +import Dict exposing (Dict(..)) +import Expect +import Morphir.IR.FQName as FQName +import Morphir.IR.Path as Path +import Morphir.IR.Type as Type +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( addFunction + , boolTypeInstance + , empType + , equalFunction + , floatTypeInstance + , intTypeInstance + , listConcatFunction + , listConcatMapFunction + , listFilterFunction + , listFilterMapFunction + , listMapFunction + , listSumFunction + , mFuncTypeOf + , mIdOf + , mIntLiteralOf + , mLambdaOf + , mLetOf + , mListOf + , mListTypeOf + , mMaybeTypeOf + , mRecordOf + , mRecordTypeOf + , mStringLiteralOf + , maybeMapFunction + , maybeWithDefaultFunction + , sCall + , sDot + , sExpCall + , sIntLit + , sLit + , sSpEqual + , sVar + , stringTypeInstance + , testDistributionName + , testDistributionPackage + ) +import Morphir.Snowpark.Constants exposing (applySnowparkFunc) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MapFunctionsMapping exposing (basicsFunctionName, checkForArgsToInline, stringsFunctionName) +import Morphir.Snowpark.MappingContext as MappingContext exposing (emptyValueMappingContext) +import Morphir.Snowpark.ReferenceUtils exposing (curryCall) +import Set +import Test exposing (Test, describe, test) + + +functionMappingsTests : Test +functionMappingsTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( calculatedContext, _, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + columnsObjects = + Dict.fromList [ ( FQName.fromString "UTest:MyMod:Emp" ":", "empColumns" ) ] + + ctx = + { emptyValueMappingContext + | typesContextInfo = calculatedContext + , packagePath = Path.fromString "UTest" + , dataFrameColumnsObjects = columnsObjects + } + + listConcatMapWithLambda = + test "Convert List.concatMap with lambda" <| + \_ -> + let + concatMapCall = + curryCall + ( listConcatMapFunction empType empType + , [ mLambdaOf ( [ "x" ], empType ) (mListOf [ mIdOf [ "x" ] empType ]) + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue concatMapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( applySnowparkFunc "array_construct" + [ applySnowparkFunc "array_construct" + [ sDot (sVar "empColumns") "firstname" + , sDot (sVar "empColumns") "lastname" + ] + ] + , "as" + ) + [ sLit "result" ] + ] + + expectedCall = + sCall + ( sCall ( expectedSelectResult, "flatten" ) [ applySnowparkFunc "col" [ sLit "result" ] ] + , "select" + ) + [ sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "value" ]) [ sIntLit 0 ] ], "as" ) + [ sLit "firstname" ] + , sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "value" ]) [ sIntLit 1 ] ], "as" ) + [ sLit "lastname" ] + ] + in + Expect.equal mapped expectedCall + + listConcatMapWithFunctionExpr = + test "Convert List.concatMap with function expr" <| + \_ -> + let + concatMapCall = + curryCall + ( listConcatMapFunction empType empType + , [ mIdOf [ "foo" ] (mFuncTypeOf empType (mListTypeOf empType)) + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue concatMapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( sExpCall (sVar "foo") [ sVar "empColumns" ] + , "as" + ) + [ sLit "result" ] + ] + + expectedCall = + sCall + ( sCall ( expectedSelectResult, "flatten" ) [ applySnowparkFunc "col" [ sLit "result" ] ] + , "select" + ) + [ sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "value" ]) [ sIntLit 0 ] ], "as" ) + [ sLit "firstname" ] + , sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "value" ]) [ sIntLit 1 ] ], "as" ) + [ sLit "lastname" ] + ] + in + Expect.equal mapped expectedCall + + listFilterMapWithLambda = + test "Convert List.filterMap with lambda" <| + \_ -> + let + fooType = + mFuncTypeOf empType (mMaybeTypeOf empType) + + fooRef = + Value.Reference fooType (FQName.fqn "UTest" "MyMod" "foo") + + filterMapCall = + curryCall + ( listFilterMapFunction empType empType + , [ mLambdaOf ( [ "x" ], empType ) (curryCall ( fooRef, [ mIdOf [ "x" ] empType ] )) + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue filterMapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( sExpCall (Scala.Ref [ "utest", "MyMod" ] "foo") [ sVar "empColumns" ] + , "as" + ) + [ sLit "result" ] + ] + + expectedFilterCall = + sCall ( expectedSelectResult, "filter" ) [ sDot (applySnowparkFunc "col" [ sLit "result" ]) "is_not_null" ] + + expectedCall = + sCall + ( expectedFilterCall, "select" ) + [ sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "result" ]) [ sIntLit 0 ] ], "as" ) + [ sLit "firstname" ] + , sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "result" ]) [ sIntLit 1 ] ], "as" ) + [ sLit "lastname" ] + ] + in + Expect.equal mapped expectedCall + + listFilterMapWithFunctionExpr = + test "Convert List.filterMap with function expression" <| + \_ -> + let + fooType = + mFuncTypeOf empType (mMaybeTypeOf empType) + + fooRef = + Value.Reference fooType (FQName.fqn "UTest" "MyMod" "foo") + + filterMapCall = + curryCall + ( listFilterMapFunction empType empType + , [ fooRef + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue filterMapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( sExpCall (Scala.Ref [ "utest", "MyMod" ] "foo") [ sVar "empColumns" ] + , "as" + ) + [ sLit "result" ] + ] + + expectedFilterCall = + sCall ( expectedSelectResult, "filter" ) [ sDot (applySnowparkFunc "col" [ sLit "result" ]) "is_not_null" ] + + expectedCall = + sCall + ( expectedFilterCall, "select" ) + [ sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "result" ]) [ sIntLit 0 ] ], "as" ) + [ sLit "firstname" ] + , sCall ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "result" ]) [ sIntLit 1 ] ], "as" ) + [ sLit "lastname" ] + ] + in + Expect.equal mapped expectedCall + + listMapWithLambdaAndRecord = + test "Convert List.map with lambda and record" <| + \_ -> + let + resultRecord = + mRecordOf [ ( "a", Value.Field stringTypeInstance (Value.Variable empType [ "x" ]) [ "firstname" ] ) ] + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "x" ], empType ) resultRecord + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( Scala.Ref [ "empColumns" ] "firstname" + , "as" + ) + [ sLit "a" ] + ] + in + Expect.equal mapped expectedSelectResult + + listMapWithLambdaAndRecordAndBinOpInProjection = + test "Convert List.map with lambda and record and binary operation in projection" <| + \_ -> + let + resultRecord = + mRecordOf + [ ( "a", Value.Field stringTypeInstance (Value.Variable empType [ "x" ]) [ "firstname" ] ) + , ( "b", curryCall ( addFunction intTypeInstance, [ mIntLiteralOf 1, mIntLiteralOf 2 ] ) ) + ] + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "x" ], empType ) resultRecord + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( Scala.Ref [ "empColumns" ] "firstname" + , "as" + ) + [ sLit "a" ] + , sCall + ( Scala.Tuple [ Scala.BinOp (applySnowparkFunc "lit" [ sIntLit 1 ]) "+" (applySnowparkFunc "lit" [ sIntLit 2 ]) ] + , "as" + ) + [ sLit "b" ] + ] + in + Expect.equal mapped expectedSelectResult + + listMapWithLambdaAndLetRecord = + test "Convert List.map with lambda and let with record" <| + \_ -> + let + resultLetRecord = + mLetOf [ "y" ] + (Value.Field stringTypeInstance (Value.Variable empType [ "k" ]) [ "lastname" ]) + (mRecordOf [ ( "a", mIdOf [ "y" ] stringTypeInstance ) ]) + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "k" ], empType ) resultLetRecord + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( Scala.Ref [ "empColumns" ] "lastname" + , "as" + ) + [ sLit "a" ] + ] + in + Expect.equal mapped expectedSelectResult + + listMapWithLambdaAndBasicType = + test "Convert List.map with lambda and basic type" <| + \_ -> + let + lambdaBody = + Value.Field stringTypeInstance (Value.Variable empType [ "k" ]) [ "lastname" ] + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "k" ], empType ) lambdaBody + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ Scala.Ref [ "empColumns" ] "lastname" ] + in + Expect.equal mapped expectedSelectResult + + listMapWithLambdaAndFieldFunction = + test "Convert List.map with lambda and field function" <| + \_ -> + let + lambdaBody = + Value.FieldFunction stringTypeInstance [ "lastname" ] + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "k" ], empType ) lambdaBody + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ applySnowparkFunc "col" [ sLit "lastname" ] ] + in + Expect.equal mapped expectedSelectResult + + listMapWithFunction = + test "Convert List.map with function expression" <| + \_ -> + let + recordType = + Type.Record () + [ { name = [ "f2" ], tpe = floatTypeInstance } + , { name = [ "f1" ], tpe = stringTypeInstance } + ] + + functionExpr = + Value.Reference (mFuncTypeOf empType recordType) (FQName.fqn "UTest" "MyMod" "myProjection") + + mapCall = + curryCall + ( listMapFunction empType empType + , [ functionExpr + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + externalSelect = + sCall ( sVar "alist", "select" ) + [ sCall + ( sExpCall (Scala.Ref [ "utest", "MyMod" ] "myProjection") [ sVar "empColumns" ] + , "as" + ) + [ sLit "result" ] + ] + + unpackSelect = + sCall ( externalSelect, "select" ) + [ sCall + ( applySnowparkFunc "as_double" [ sExpCall (applySnowparkFunc "col" [ sLit "result" ]) [ sIntLit 0 ] ] + , "as" + ) + [ sLit "f2" ] + , sCall + ( applySnowparkFunc "as_char" [ sExpCall (applySnowparkFunc "col" [ sLit "result" ]) [ sIntLit 1 ] ] + , "as" + ) + [ sLit "f1" ] + ] + in + Expect.equal mapped unpackSelect + + listMapWithLambdaAndRecordUpdate = + test "Convert List.map with record update expression" <| + \_ -> + let + resultUpdateRecord = + Value.UpdateRecord + empType + (mIdOf [ "k" ] empType) + (Dict.fromList [ ( [ "lastname" ], mIdOf [ "tmpStr" ] stringTypeInstance ) ]) + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "k" ], empType ) resultUpdateRecord + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall ctx + + expectedSelectResult = + sCall ( sVar "alist", "withColumns" ) + [ sExpCall + (Scala.Variable "Seq") + [ sLit "lastname" ] + , sExpCall + (Scala.Variable "Seq") + [ sVar "tmpStr" ] + ] + in + Expect.equal mapped expectedSelectResult + + listFilterWithLambdaAndBasicCondition = + test "Convert List.filter with lambda and basic condition" <| + \_ -> + let + lambdaBody = + curryCall + ( equalFunction stringTypeInstance + , [ mStringLiteralOf "Smith" + , Value.Field stringTypeInstance (Value.Variable empType [ "k" ]) [ "lastname" ] + ] + ) + + filterCall = + curryCall + ( listFilterFunction empType empType + , [ mLambdaOf ( [ "k" ], empType ) lambdaBody + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue filterCall ctx + + expectedResult = + sCall + ( sVar "alist", "filter" ) + [ sSpEqual (applySnowparkFunc "lit" [ sLit "Smith" ]) (Scala.Ref [ "empColumns" ] "lastname") ] + in + Expect.equal mapped expectedResult + + listFilterWithPredicateFunction = + test "Convert List.filter with predicate function" <| + \_ -> + let + referenceToFunc = + Value.Reference (mFuncTypeOf empType boolTypeInstance) (FQName.fqn "UTest" "MyMod" "myPredicate") + + filterCall = + curryCall + ( listFilterFunction empType empType + , [ referenceToFunc + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue filterCall ctx + + expectedResult = + sCall + ( sVar "alist", "filter" ) + [ sExpCall (Scala.Ref [ "utest", "MyMod" ] "myPredicate") [ Scala.Variable "empColumns" ] ] + in + Expect.equal mapped expectedResult + + listFilterWithArgPredicateFunction = + test "Convert List.filter with predicate function as argument" <| + \_ -> + let + referenceToFunc = + Value.Variable (mFuncTypeOf empType boolTypeInstance) [ "my", "predicate" ] + + filterCall = + curryCall + ( listFilterFunction empType empType + , [ referenceToFunc + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue filterCall ctx + + expectedResult = + sCall + ( sVar "alist", "filter" ) + [ sExpCall (Scala.Variable "myPredicate") [ Scala.Variable "empColumns" ] ] + in + Expect.equal mapped expectedResult + + listFilterWithPartiallyAppliedFunction = + test "Convert List.filter with partially applied function" <| + \_ -> + let + predicateType = + mFuncTypeOf stringTypeInstance (mFuncTypeOf empType boolTypeInstance) + + referenceToFunc = + curryCall + ( Value.Reference predicateType (FQName.fqn "UTest" "MyMod" "checkLastName") + , [ mStringLiteralOf "Smith" ] + ) + + filterCall = + curryCall + ( listFilterFunction empType empType + , [ referenceToFunc + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue filterCall ctx + + expectedResult = + sCall + ( sVar "alist", "filter" ) + [ sExpCall + (sExpCall (Scala.Ref [ "utest", "MyMod" ] "checkLastName") [ applySnowparkFunc "lit" [ sLit "Smith" ] ]) + [ Scala.Variable "empColumns" ] + ] + in + Expect.equal mapped expectedResult + + listConcatToArray = + test "Convert List.concat to array" <| + \_ -> + let + utilFunctionName = + FQName.fqn "UTest" "MyMod" "apply" + + funcType = + mFuncTypeOf stringTypeInstance (mListTypeOf empType) + + referenceToFunc = + curryCall + ( Value.Reference funcType utilFunctionName + , [ mStringLiteralOf "X11" ] + ) + + concatCall = + curryCall + ( listConcatFunction empType + , [ mListOf [ referenceToFunc ] ] + ) + + newCtx = + { ctx | functionClassificationInfo = Dict.fromList [ ( utilFunctionName, MappingContext.FromDfValuesToDfValues ) ] } + + ( mapped, _ ) = + mapValue concatCall newCtx + + argsArrayConstruct = + applySnowparkFunc + "array_construct" + [ sExpCall (Scala.Ref [ "utest", "MyMod" ] "apply") [ applySnowparkFunc "lit" [ sLit "X11" ] ] ] + + expectedResult = + applySnowparkFunc "callBuiltin" [ sLit "array_flatten", argsArrayConstruct ] + in + Expect.equal mapped expectedResult + + listConcatToDataFrameUnion = + test "Convert List.concat to DataFrame union" <| + \_ -> + let + utilFunctionName = + FQName.fqn "UTest" "MyMod" "apply" + + funcType = + mFuncTypeOf stringTypeInstance (mListTypeOf empType) + + referenceToFunc txt = + curryCall + ( Value.Reference funcType utilFunctionName + , [ mStringLiteralOf txt ] + ) + + concatCall = + curryCall + ( listConcatFunction empType + , [ mListOf [ referenceToFunc "A", referenceToFunc "B" ] ] + ) + + ( mapped, _ ) = + mapValue concatCall ctx + + unionCall = + sCall + ( sExpCall (Scala.Ref [ "utest", "MyMod" ] "apply") [ applySnowparkFunc "lit" [ sLit "A" ] ], "unionAll" ) + [ sExpCall (Scala.Ref [ "utest", "MyMod" ] "apply") [ applySnowparkFunc "lit" [ sLit "B" ] ] ] + in + Expect.equal mapped unionCall + + listSumWithMap = + test "Generate List.sum" <| + \_ -> + let + mapLambdaBody = + curryCall + ( Value.Reference (mFuncTypeOf stringTypeInstance intTypeInstance) (stringsFunctionName [ "length" ]) + , [ Value.FieldFunction stringTypeInstance [ "lastname" ] ] + ) + + mapCall = + curryCall + ( listMapFunction empType intTypeInstance + , [ mLambdaOf ( [ "k" ], empType ) mapLambdaBody + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + sumCall = + curryCall + ( listSumFunction intTypeInstance + , [ mapCall ] + ) + + ( mapped, _ ) = + mapValue sumCall ctx + + selectCall = + sCall + ( sVar "alist", "select" ) + [ sCall + ( applySnowparkFunc "length" [ applySnowparkFunc "col" [ sLit "lastname" ] ], "as" ) + [ sLit "result" ] + ] + + targetSumCall = + sCall ( selectCall, "select" ) [ applySnowparkFunc "coalesce" [ applySnowparkFunc "sum" [ applySnowparkFunc "col" [ sLit "result" ] ], applySnowparkFunc "lit" [ sIntLit 0 ] ] ] + + expected = + sCall ( sDot (sDot targetSumCall "first") "get", "getInt" ) [ sIntLit 0 ] + in + Expect.equal mapped expected + + maybeMapWithFunction = + test "Generate Maybe.map with function expression" <| + \_ -> + let + referenceToFunc = + Value.Reference (mFuncTypeOf empType boolTypeInstance) (FQName.fqn "UTest" "MyMod" "myOperation") + + filterCall = + curryCall + ( maybeMapFunction stringTypeInstance intTypeInstance + , [ referenceToFunc + , mIdOf [ "mval" ] (mMaybeTypeOf stringTypeInstance) + ] + ) + + ( mapped, _ ) = + mapValue filterCall ctx + + expectedResult = + sCall + ( applySnowparkFunc "when" + [ sDot (sVar "mval") "is_not_null" + , sExpCall (Scala.Ref [ "utest", "MyMod" ] "myOperation") [ sVar "mval" ] + ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ Scala.Literal Scala.NullLit ] ] + in + Expect.equal mapped expectedResult + + maybeMapWithLambda = + test "Generate Maybe.map with lambda expression" <| + \_ -> + let + plusType = + mFuncTypeOf intTypeInstance (mFuncTypeOf intTypeInstance intTypeInstance) + + lambdaBody = + curryCall + ( Value.Reference plusType (basicsFunctionName [ "add" ]) + , [ mIdOf [ "k" ] intTypeInstance + , mIntLiteralOf 10 + ] + ) + + filterCall = + curryCall + ( maybeMapFunction stringTypeInstance intTypeInstance + , [ mLambdaOf ( [ "k" ], empType ) lambdaBody + , mIdOf [ "mval" ] (mMaybeTypeOf stringTypeInstance) + ] + ) + + ( mapped, _ ) = + mapValue filterCall ctx + + expectedResult = + sCall + ( applySnowparkFunc "when" + [ sDot (sVar "mval") "is_not_null" + , Scala.BinOp (sVar "mval") "+" (applySnowparkFunc "lit" [ sIntLit 10 ]) + ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ Scala.Literal Scala.NullLit ] ] + in + Expect.equal mapped expectedResult + + maybeWithDefault = + test "Generate Maybe.withDefault" <| + \_ -> + let + withDefaultCall = + curryCall + ( maybeWithDefaultFunction stringTypeInstance + , [ mStringLiteralOf "A" + , mIdOf [ "mval" ] (mMaybeTypeOf stringTypeInstance) + ] + ) + + ( mapped, _ ) = + mapValue withDefaultCall ctx + + expectedResult = + applySnowparkFunc "coalesce" [ sVar "mval", applySnowparkFunc "lit" [ sLit "A" ] ] + in + Expect.equal mapped expectedResult + + argInliningFunctionByName = + test "argument inlining from named referece" <| + \_ -> + let + functionToInlineName = + FQName.fqn "UTest" "MyMod" "Foo" + + definitionToInline = + { inputTypes = + [ ( [ "x" ], intTypeInstance, intTypeInstance ) + , ( [ "y" ], floatTypeInstance, floatTypeInstance ) + , ( [ "z" ], stringTypeInstance, stringTypeInstance ) + ] + , outputType = stringTypeInstance + , body = mIdOf [ "x" ] intTypeInstance + } + + newCtx = + { ctx | globalValuesToInline = Dict.insert functionToInlineName definitionToInline ctx.globalValuesToInline } + + inlined = + checkForArgsToInline + newCtx + [ Value.Reference + (mFuncTypeOf intTypeInstance + (mFuncTypeOf floatTypeInstance + (mFuncTypeOf stringTypeInstance stringTypeInstance) + ) + ) + functionToInlineName + ] + + expectedResult = + [ mLambdaOf ( [ "x" ], intTypeInstance ) + (mLambdaOf ( [ "y" ], floatTypeInstance ) + (mLambdaOf ( [ "z" ], stringTypeInstance ) + (mIdOf [ "x" ] intTypeInstance) + ) + ) + ] + in + Expect.equal inlined expectedResult + + argInliningFunctionByCall = + test "argument inlining from call" <| + \_ -> + let + functionToInlineName = + FQName.fqn "UTest" "MyMod" "Foo" + + definitionToInline = + { inputTypes = [ ( [ "x" ], intTypeInstance, intTypeInstance ) ] + , outputType = intTypeInstance + , body = curryCall ( addFunction intTypeInstance, [ mIdOf [ "x" ] intTypeInstance, mIdOf [ "x" ] intTypeInstance ] ) + } + + newCtx = + { ctx | globalValuesToInline = Dict.insert functionToInlineName definitionToInline ctx.globalValuesToInline } + + inlined = + checkForArgsToInline + newCtx + [ curryCall + ( Value.Reference + (mFuncTypeOf intTypeInstance intTypeInstance) + functionToInlineName + , [ mIntLiteralOf 100 ] + ) + ] + + expectedResult = + [ curryCall ( addFunction intTypeInstance, [ mIntLiteralOf 100, mIntLiteralOf 100 ] ) ] + in + Expect.equal inlined expectedResult + + listMapWithInlining = + test "Convert List.map with lambda function inlining" <| + \_ -> + let + functionToInlineName = + FQName.fqn "UTest" "MyMod" "Foo" + + resultRecordType = + mRecordTypeOf [ ( "t", stringTypeInstance ) ] + + definitionToInline = + { inputTypes = [ ( [ "k" ], empType, empType ) ] + , outputType = resultRecordType + , body = mRecordOf [ ( "t", Value.Field stringTypeInstance (Value.Variable empType [ "k" ]) [ "lastname" ] ) ] + } + + newCtx = + { ctx | globalValuesToInline = Dict.insert functionToInlineName definitionToInline ctx.globalValuesToInline } + + mapCall = + curryCall + ( listMapFunction empType empType + , [ mLambdaOf ( [ "k" ], empType ) (curryCall ( Value.Reference (mFuncTypeOf empType resultRecordType) functionToInlineName, [ mIdOf [ "k" ] empType ] )) + , mIdOf [ "alist" ] (mListTypeOf empType) + ] + ) + + ( mapped, _ ) = + mapValue mapCall newCtx + + expectedSelectResult = + sCall ( sVar "alist", "select" ) + [ sCall + ( Scala.Ref [ "empColumns" ] "lastname" + , "as" + ) + [ sLit "t" ] + ] + in + Expect.equal mapped expectedSelectResult + in + describe "Function mappings tests" + [ listConcatMapWithLambda + , listConcatMapWithFunctionExpr + , listFilterMapWithLambda + , listFilterMapWithFunctionExpr + , listMapWithLambdaAndRecord + , listMapWithLambdaAndRecordAndBinOpInProjection + , listMapWithLambdaAndLetRecord + , listMapWithLambdaAndBasicType + , listMapWithLambdaAndFieldFunction + , listMapWithFunction + , listMapWithLambdaAndRecordUpdate + , listFilterWithLambdaAndBasicCondition + , listFilterWithPredicateFunction + , listFilterWithArgPredicateFunction + , listFilterWithPartiallyAppliedFunction + , listConcatToArray + , listConcatToDataFrameUnion + , listSumWithMap + , maybeMapWithFunction + , maybeMapWithLambda + , maybeWithDefault + , argInliningFunctionByName + , argInliningFunctionByCall + , listMapWithInlining + ] diff --git a/tests/Morphir/Snowpark/MapValueJoinTests.elm b/tests/Morphir/Snowpark/MapValueJoinTests.elm new file mode 100644 index 000000000..a23eff4a7 --- /dev/null +++ b/tests/Morphir/Snowpark/MapValueJoinTests.elm @@ -0,0 +1,358 @@ +module Morphir.Snowpark.MapValueJoinTests exposing (..) + +import Dict exposing (Dict(..)) +import Expect +import Morphir.IR.FQName as FQName +import Morphir.IR.Path as Path +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value as ValueIR +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( boolTypeInstance + , equalFunction + , innerJoinFunction + , intTypeInstance + , leftJoinFunction + , listMapFunction + , mField + , mFuncTypeOf + , mIdOf + , mLambdaOf + , mListTypeOf + , mMaybeTypeOf + , mRecordOf + , mRecordTypeOf + , mTuple2TypeOf + , maybeMapFunction + , sCall + , sLit + , sVar + , testDistributionName + , testDistributionPackage + , typeA + , typeB + , typeC + ) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext as MappingContext exposing (emptyValueMappingContext) +import Morphir.Snowpark.ReferenceUtils exposing (curryCall) +import Set +import Test exposing (Test, describe, test) + + +expectedInnerJoin : Scala.Value +expectedInnerJoin = + sCall ( expectedJoinCall "inner", "select" ) expectedProjection + + +expectedLeftJoin : Scala.Value +expectedLeftJoin = + sCall ( expectedJoinCall "left", "select" ) expectedProjection + + +expectedMultipleJoin : Scala.Value +expectedMultipleJoin = + sCall ( expectedInnerMultipleJoin, "select" ) expectedMultipleProjection + + +expectedInnerMultipleJoin : Scala.Value +expectedInnerMultipleJoin = + sCall ( expectedInnerInnerMultipleJoin, "join" ) expectedInnerJoinValue + + +expectedInnerInnerMultipleJoin : Scala.Value +expectedInnerInnerMultipleJoin = + sCall ( sVar "dataSetA", "join" ) expectedInnerInnerJoinValue + + +expectedInnerJoinValue : List Scala.Value +expectedInnerJoinValue = + [ sVar "dataSetC" + , Scala.BinOp (Scala.Ref [ "typeAColumns" ] "id") "===" (Scala.Ref [ "typeCColumns" ] "id") + , sLit "inner" + ] + + +expectedInnerInnerJoinValue : List Scala.Value +expectedInnerInnerJoinValue = + [ sVar "dataSetB" + , Scala.BinOp (Scala.Ref [ "typeAColumns" ] "id") "===" (Scala.Ref [ "typeBColumns" ] "id") + , sLit "inner" + ] + + +expectedProjection : List Scala.Value +expectedProjection = + [ sCall ( Scala.Ref [ "typeAColumns" ] "id", "alias" ) [ sLit "idA" ] + , sCall ( Scala.Ref [ "typeBColumns" ] "id", "alias" ) [ sLit "idB" ] + ] + + +expectedMultipleProjection : List Scala.Value +expectedMultipleProjection = + [ sCall ( Scala.Ref [ "typeAColumns" ] "id", "alias" ) [ sLit "idA" ] + , sCall ( Scala.Ref [ "typeBColumns" ] "id", "alias" ) [ sLit "idB" ] + , sCall ( Scala.Ref [ "typeCColumns" ] "id", "alias" ) [ sLit "idC" ] + ] + + +expectedJoinCall : String -> Scala.Value +expectedJoinCall joinType = + sCall + ( sVar "dataSetA", "join" ) + [ sVar "dataSetB" + , Scala.BinOp (Scala.Ref [ "typeAColumns" ] "id") "===" (Scala.Ref [ "typeBColumns" ] "id") + , sLit joinType + ] + + +originMultipleInnerJoin : ValueIR.TypedValue +originMultipleInnerJoin = + let + tupleType = + mTuple2TypeOf typeA typeB + in + curryCall + ( innerJoinFunction typeC tupleType + , [ mIdOf [ "dataSetC" ] (mListTypeOf typeC) + , ValueIR.Lambda + (mFuncTypeOf tupleType (mFuncTypeOf typeC boolTypeInstance)) + (ValueIR.TuplePattern + tupleType + [ ValueIR.AsPattern typeA (ValueIR.WildcardPattern typeA) [ "x" ] + , ValueIR.AsPattern typeB (ValueIR.WildcardPattern typeB) [ "y" ] + ] + ) + (mLambdaOf + ( [ "z" ], typeC ) + (curryCall + ( equalFunction intTypeInstance + , [ mField intTypeInstance (mIdOf [ "x" ] typeA) "id" + , mField intTypeInstance (mIdOf [ "z" ] typeC) "id" + ] + ) + ) + ) + , originInnerJoin + ] + ) + + +originInnerJoin : ValueIR.TypedValue +originInnerJoin = + curryCall + ( innerJoinFunction typeA typeB + , [ mIdOf [ "dataSetB" ] (mListTypeOf typeB) + , mLambdaOf + ( [ "a" ], typeA ) + (mLambdaOf + ( [ "b" ], typeB ) + (curryCall + ( equalFunction intTypeInstance + , [ mField intTypeInstance (mIdOf [ "a" ] typeA) "id" + , mField intTypeInstance (mIdOf [ "b" ] typeB) "id" + ] + ) + ) + ) + , mIdOf [ "dataSetA" ] (mListTypeOf typeA) + ] + ) + + +originLeftJoin : ValueIR.TypedValue +originLeftJoin = + curryCall + ( leftJoinFunction typeA typeB + , [ mIdOf [ "dataSetB" ] (mListTypeOf typeB) + , mLambdaOf + ( [ "a" ], typeA ) + (mLambdaOf + ( [ "b" ], typeB ) + (curryCall + ( equalFunction intTypeInstance + , [ mField intTypeInstance (mIdOf [ "a" ] typeA) "id" + , mField intTypeInstance (mIdOf [ "b" ] typeB) "id" + ] + ) + ) + ) + , mIdOf [ "dataSetA" ] (mListTypeOf typeA) + ] + ) + + +projectionInnerJoin : ValueIR.Value () (TypeIR.Type ()) +projectionInnerJoin = + let + tupleType = + mTuple2TypeOf typeA typeB + in + curryCall + ( listMapFunction tupleType recordProjection + , [ ValueIR.Lambda + (mFuncTypeOf tupleType recordProjection) + (ValueIR.TuplePattern + tupleType + [ ValueIR.AsPattern typeA (ValueIR.WildcardPattern typeA) [ "x" ] + , ValueIR.AsPattern typeB (ValueIR.WildcardPattern typeB) [ "y" ] + ] + ) + (mRecordOf + [ ( "idA", mField intTypeInstance (mIdOf [ "x" ] typeA) "id" ) + , ( "idB", mField intTypeInstance (mIdOf [ "y" ] typeB) "id" ) + ] + ) + , originInnerJoin + ] + ) + + +projectionLeftJoin : ValueIR.Value () (TypeIR.Type ()) +projectionLeftJoin = + let + tupleType = + mTuple2TypeOf typeA (mMaybeTypeOf typeB) + in + curryCall + ( listMapFunction tupleType recordMaybeProjection + , [ ValueIR.Lambda + (mFuncTypeOf tupleType recordMaybeProjection) + (ValueIR.TuplePattern + tupleType + [ ValueIR.AsPattern typeA (ValueIR.WildcardPattern typeA) [ "x" ] + , ValueIR.AsPattern typeB (ValueIR.WildcardPattern (mMaybeTypeOf intTypeInstance)) [ "y" ] + ] + ) + (mRecordOf + [ ( "idA", mField intTypeInstance (mIdOf [ "x" ] typeA) "id" ) + , ( "idB" + , curryCall + ( maybeMapFunction typeB intTypeInstance + , [ mLambdaOf ( [ "z" ], typeB ) (mField typeB (mIdOf [ "z" ] typeB) "id") + , mIdOf [ "y" ] (mMaybeTypeOf typeB) + ] + ) + ) + ] + ) + , originLeftJoin + ] + ) + + +projectionMultipleJoin : ValueIR.Value () (TypeIR.Type ()) +projectionMultipleJoin = + let + tupleType = + mTuple2TypeOf typeA typeB + + tupleTupleType = + mTuple2TypeOf tupleType typeC + in + curryCall + ( listMapFunction tupleTupleType recordMultipleProjection + , [ ValueIR.Lambda + (mFuncTypeOf tupleTupleType recordMultipleProjection) + (ValueIR.TuplePattern + tupleTupleType + [ ValueIR.TuplePattern + tupleType + [ ValueIR.AsPattern typeA (ValueIR.WildcardPattern typeA) [ "a" ] + , ValueIR.AsPattern typeB (ValueIR.WildcardPattern typeB) [ "b" ] + ] + , ValueIR.AsPattern typeC (ValueIR.WildcardPattern typeC) [ "c" ] + ] + ) + (mRecordOf + [ ( "idA", mField intTypeInstance (mIdOf [ "a" ] typeA) "id" ) + , ( "idB", mField intTypeInstance (mIdOf [ "b" ] typeB) "id" ) + , ( "idC", mField intTypeInstance (mIdOf [ "c" ] typeC) "id" ) + ] + ) + , originMultipleInnerJoin + ] + ) + + +recordProjection : TypeIR.Type () +recordProjection = + mRecordTypeOf + [ ( "idA", intTypeInstance ) + , ( "idB", intTypeInstance ) + ] + + +recordMaybeProjection : TypeIR.Type () +recordMaybeProjection = + mRecordTypeOf + [ ( "idA", intTypeInstance ) + , ( "idB", mMaybeTypeOf intTypeInstance ) + ] + + +recordMultipleProjection : TypeIR.Type () +recordMultipleProjection = + mRecordTypeOf + [ ( "idA", intTypeInstance ) + , ( "idB", intTypeInstance ) + , ( "idC", intTypeInstance ) + ] + + +mapValueJoinTest : Test +mapValueJoinTest = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( calculatedContext, _, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + columnsObjects = + Dict.fromList + [ ( FQName.fromString "UTest:MyMod:TypeA" ":", "typeAColumns" ) + , ( FQName.fromString "UTest:MyMod:TypeB" ":", "typeBColumns" ) + , ( FQName.fromString "UTest:MyMod:TypeC" ":", "typeCColumns" ) + ] + + ctx = + { emptyValueMappingContext + | typesContextInfo = calculatedContext + , packagePath = Path.fromString "UTest" + , dataFrameColumnsObjects = columnsObjects + } + + assertInnerJoin = + test "simple inner Join" <| + \_ -> + let + ( mapped, _ ) = + mapValue projectionInnerJoin ctx + in + Expect.equal mapped expectedInnerJoin + + assertLeftJoin = + test "simple left Join" <| + \_ -> + let + ( mapped, _ ) = + mapValue projectionLeftJoin ctx + in + Expect.equal mapped expectedLeftJoin + + assertMultipleJoin = + test "Multiple inner Join" <| + \_ -> + let + ( mapped, _ ) = + mapValue projectionMultipleJoin ctx + in + Expect.equal mapped expectedMultipleJoin + in + describe "inner Join" + [ assertInnerJoin + , assertLeftJoin + , assertMultipleJoin + ] diff --git a/tests/Morphir/Snowpark/MapValueListTests.elm b/tests/Morphir/Snowpark/MapValueListTests.elm new file mode 100644 index 000000000..248a425bc --- /dev/null +++ b/tests/Morphir/Snowpark/MapValueListTests.elm @@ -0,0 +1,110 @@ +module Morphir.Snowpark.MapValueListTests exposing (mapValueListTest) + +import Expect +import Morphir.IR.Literal as Literal +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value as ValueIR +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils exposing (morphirNamespace) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext exposing (emptyValueMappingContext) +import Test exposing (Test, describe, test) + + +createLiteral : String -> ValueIR.Value va (TypeIR.Type ()) +createLiteral name = + ValueIR.Literal + (TypeIR.Reference + () + ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) + [] + ) + (Literal.StringLiteral name) + + +listTest : ValueIR.Value ta (TypeIR.Type ()) +listTest = + ValueIR.List + (TypeIR.Reference + () + ( morphirNamespace, [ [ "list" ] ], [ "list" ] ) + [ TypeIR.Reference + () + ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) + [] + ] + ) + [ createLiteral "a" + , createLiteral "b" + , createLiteral "c" + ] + + +itemList : String -> Scala.Value +itemList name = + Scala.Apply (Scala.Ref [ "com", "snowflake", "snowpark", "functions" ] "lit") + [ Scala.ArgValue Nothing (Scala.Literal (Scala.StringLit name)) ] + + +listExpectedTest : Scala.Value +listExpectedTest = + Scala.Apply + (Scala.Variable "Seq") + [ Scala.ArgValue Nothing (itemList "a") + , Scala.ArgValue Nothing (itemList "b") + , Scala.ArgValue Nothing (itemList "c") + ] + + +memberTest : ValueIR.Value ta (TypeIR.Type ()) +memberTest = + ValueIR.Apply + (TypeIR.Reference () ( morphirNamespace, [ [ "basics" ] ], [ "bool" ] ) []) + (ValueIR.Apply + (TypeIR.Function + () + (TypeIR.Reference () ( morphirNamespace, [ [ "list" ] ], [ "list" ] ) [ TypeIR.Reference () ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) [] ]) + (TypeIR.Reference () ( morphirNamespace, [ [ "basics" ] ], [ "bool" ] ) []) + ) + (ValueIR.Reference + (TypeIR.Function () (TypeIR.Reference () ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) []) (TypeIR.Function () (TypeIR.Reference () ( morphirNamespace, [ [ "list" ] ], [ "list" ] ) [ TypeIR.Reference () ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) [] ]) (TypeIR.Reference () ( morphirNamespace, [ [ "basics" ] ], [ "bool" ] ) []))) + ( morphirNamespace, [ [ "list" ] ], [ "member" ] ) + ) + (ValueIR.Variable (TypeIR.Reference () ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) []) [ "v" ]) + ) + listTest + + +memberExpectedTest : Scala.Value +memberExpectedTest = + Scala.Apply (Scala.Select (Scala.Variable "v") "in") [ Scala.ArgValue Nothing listExpectedTest ] + + +mapValueListTest : Test +mapValueListTest = + let + emptyContext = + emptyValueMappingContext + + assertListTest = + test "list" <| + \_ -> + let + ( mapped, _ ) = + mapValue listTest emptyContext + in + Expect.equal mapped listExpectedTest + + assertMemberTest = + test "member list" <| + \_ -> + let + ( mapped, _ ) = + mapValue memberTest emptyContext + in + Expect.equal mapped memberExpectedTest + in + describe "List functions" + [ assertListTest + , assertMemberTest + ] diff --git a/tests/Morphir/Snowpark/MapValueLiteralTests.elm b/tests/Morphir/Snowpark/MapValueLiteralTests.elm new file mode 100644 index 000000000..fd1e235db --- /dev/null +++ b/tests/Morphir/Snowpark/MapValueLiteralTests.elm @@ -0,0 +1,293 @@ +module Morphir.Snowpark.MapValueLiteralTests exposing + ( mapIfValueExpressionsTests + , mapLetValueExpressionsTests + , mapValueLiteralTests + ) + +import Expect +import Morphir.IR.Literal as Literal +import Morphir.IR.Type as Type +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( addFunction + , intTypeInstance + , mFuncTypeOf + , mIdOf + , mIntLiteralOf + , mLetOf + , sBlock + , sCall + , sExpCall + , sIntLit + , sVar + ) +import Morphir.Snowpark.Constants as Constants exposing (applySnowparkFunc) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext exposing (emptyValueMappingContext) +import Morphir.Snowpark.ReferenceUtils exposing (curryCall) +import Test exposing (Test, describe, test) + + +functionNamespace : List String +functionNamespace = + [ "com", "snowflake", "snowpark", "functions" ] + + +booleanReference : Type.Type () +booleanReference = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "boolean" ] ) [] + + +booleanTest : Scala.Value +booleanTest = + Scala.Apply + (Scala.Ref functionNamespace "lit") + [ Scala.ArgValue + Nothing + (Scala.Literal (Scala.BooleanLit True)) + ] + + +stringReference : Type.Type () +stringReference = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "boolean" ] ) [] + + +stringTest : Scala.Value +stringTest = + Scala.Apply + (Scala.Ref functionNamespace "lit") + [ Scala.ArgValue + Nothing + (Scala.Literal (Scala.StringLit "Hello world")) + ] + + +characterReference : Type.Type () +characterReference = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "character" ] ) [] + + +characterTest : Scala.Value +characterTest = + Scala.Apply + (Scala.Ref functionNamespace "lit") + [ Scala.ArgValue + Nothing + (Scala.Literal (Scala.CharacterLit 'C')) + ] + + +floatReference : Type.Type () +floatReference = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) [] + + +floatTest : Scala.Value +floatTest = + Scala.Apply + (Scala.Ref functionNamespace "lit") + [ Scala.ArgValue + Nothing + (Scala.Literal (Scala.FloatLit 3.24)) + ] + + +integerReference : Type.Type () +integerReference = + Type.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "integer" ] ) [] + + +integerTest : Scala.Value +integerTest = + Scala.Apply + (Scala.Ref functionNamespace "lit") + [ Scala.ArgValue + Nothing + (Scala.Literal (Scala.IntegerLit 5)) + ] + + +mapValueLiteralTests : Test +mapValueLiteralTests = + let + emptyContext = + emptyValueMappingContext + + assertBooleanLiteral = + test "Convert boolean" <| + \_ -> + let + ( mapped, _ ) = + mapValue (Value.Literal booleanReference (Literal.BoolLiteral True)) emptyContext + in + Expect.equal booleanTest mapped + + assertStringLiteral = + test "Convert string" <| + \_ -> + let + ( mapped, _ ) = + mapValue (Value.Literal stringReference (Literal.StringLiteral "Hello world")) emptyContext + in + Expect.equal stringTest mapped + + assertCharacterLiteral = + test "Convert character" <| + \_ -> + let + ( mapped, _ ) = + mapValue (Value.Literal characterReference (Literal.CharLiteral 'C')) emptyContext + in + Expect.equal characterTest mapped + + assertFloatLiteral = + test "Convert float" <| + \_ -> + let + ( mapped, _ ) = + mapValue (Value.Literal floatReference (Literal.FloatLiteral 3.24)) emptyContext + in + Expect.equal floatTest mapped + + assertIntegerLiteral = + test "Convert integer" <| + \_ -> + let + ( mapped, _ ) = + mapValue (Value.Literal integerReference (Literal.WholeNumberLiteral 5)) emptyContext + in + Expect.equal integerTest mapped + in + describe "literalMapTransform" + [ assertBooleanLiteral + , assertStringLiteral + , assertCharacterLiteral + , assertFloatLiteral + , assertIntegerLiteral + ] + + +mapIfValueExpressionsTests : Test +mapIfValueExpressionsTests = + let + emptyContext = + emptyValueMappingContext + + assertIfExprGeneration = + test "Generation for if expressions" <| + \_ -> + let + ifExample = + Value.IfThenElse intTypeInstance (mIdOf [ "flag" ] booleanReference) (mIntLiteralOf 10) (mIntLiteralOf 20) + + ( mapped, _ ) = + mapValue ifExample emptyContext + + expectedIf = + sCall + ( applySnowparkFunc "when" [ sVar "flag", applySnowparkFunc "lit" [ sIntLit 10 ] ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sIntLit 20 ] ] + in + Expect.equal expectedIf mapped + in + describe "IF Value mappings" + [ assertIfExprGeneration + ] + + +mapLetValueExpressionsTests : Test +mapLetValueExpressionsTests = + let + emptyContext = + emptyValueMappingContext + + assertLetExprGenerationWithOneBinding = + test "Generation for let expressions with one binding" <| + \_ -> + let + letExample = + mLetOf [ "tmp" ] (mIntLiteralOf 10) (curryCall ( addFunction intTypeInstance, [ mIdOf [ "tmp" ] intTypeInstance, mIntLiteralOf 10 ] )) + + ( mapped, _ ) = + mapValue letExample emptyContext + + expectedVal = + sBlock (Scala.BinOp (sVar "tmp") "+" (applySnowparkFunc "lit" [ sIntLit 10 ])) + [ ( "tmp", applySnowparkFunc "lit" [ sIntLit 10 ] ) ] + in + Expect.equal expectedVal mapped + + assertLetExprGenerationWithSeveralBindings = + test "Generation for let expressions with several bindings" <| + \_ -> + let + letExample = + mLetOf [ "tmp1" ] (mIntLiteralOf 10) <| + mLetOf [ "tmp2" ] (mIntLiteralOf 20) <| + mLetOf [ "tmp3" ] (mIntLiteralOf 30) (curryCall ( addFunction intTypeInstance, [ mIdOf [ "tmp1" ] intTypeInstance, mIntLiteralOf 10 ] )) + + ( mapped, _ ) = + mapValue letExample emptyContext + + expectedVal = + sBlock (Scala.BinOp (sVar "tmp1") "+" (applySnowparkFunc "lit" [ sIntLit 10 ])) + [ ( "tmp1", applySnowparkFunc "lit" [ sIntLit 10 ] ) + , ( "tmp2", applySnowparkFunc "lit" [ sIntLit 20 ] ) + , ( "tmp3", applySnowparkFunc "lit" [ sIntLit 30 ] ) + ] + in + Expect.equal expectedVal mapped + + assertLetExprGenerationWithFunctionDecl = + test "Generation for let expressions with function decls" <| + \_ -> + let + userDefinedFuncType = + mFuncTypeOf intTypeInstance (mFuncTypeOf intTypeInstance intTypeInstance) + + letLambda = + Value.Lambda userDefinedFuncType + (Value.AsPattern intTypeInstance (Value.WildcardPattern intTypeInstance) [ "x" ]) + (curryCall ( addFunction intTypeInstance, [ mIdOf [ "x" ] intTypeInstance, mIdOf [ "x" ] intTypeInstance ] )) + + letExample = + Value.LetDefinition + userDefinedFuncType + [ "double" ] + { inputTypes = [] + , outputType = userDefinedFuncType + , body = letLambda + } + (curryCall ( mIdOf [ "double" ] userDefinedFuncType, [ mIdOf [ "tmp1" ] intTypeInstance ] )) + + ( mapped, _ ) = + mapValue letExample emptyContext + + lambdaArgDecl = + { modifiers = [], tpe = Constants.typeRefForSnowparkType "Column", name = "x", defaultValue = Nothing } + + expectedVal = + Scala.Block + [ Scala.FunctionDecl + { modifiers = [] + , name = "double" + , typeArgs = [] + , args = [ [ lambdaArgDecl ] ] + , returnType = Nothing + , body = Just <| Scala.BinOp (sVar "x") "+" (sVar "x") + } + ] + (sExpCall (sVar "double") [ sVar "tmp1" ]) + in + Expect.equal expectedVal mapped + in + describe "Let Value mappings" + [ assertLetExprGenerationWithOneBinding + , assertLetExprGenerationWithSeveralBindings + , assertLetExprGenerationWithFunctionDecl + ] diff --git a/tests/Morphir/Snowpark/MapValueOperatorTests.elm b/tests/Morphir/Snowpark/MapValueOperatorTests.elm new file mode 100644 index 000000000..fc28ac3f9 --- /dev/null +++ b/tests/Morphir/Snowpark/MapValueOperatorTests.elm @@ -0,0 +1,186 @@ +module Morphir.Snowpark.MapValueOperatorTests exposing (mapValueListTest) + +import Expect +import Morphir.IR.Literal as Literal +import Morphir.IR.Type as TypeIR +import Morphir.IR.Value as ValueIR +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( floatTypeInstance + , intTypeInstance + , mFloatLiteralOf + , mFuncTypeOf + , mIntLiteralOf + , morphirNamespace + , sExpCall + , sFloatLit + , sSnowparkRefFuncion + ) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MappingContext exposing (emptyValueMappingContext) +import Test exposing (Test, describe, test) + + +createNumberLiteral : Int -> ValueIR.Value va (TypeIR.Type ()) +createNumberLiteral number = + ValueIR.Literal + (TypeIR.Reference + () + ( morphirNamespace, [ [ "string" ] ], [ "string" ] ) + [] + ) + (Literal.WholeNumberLiteral number) + + +floorInput : ValueIR.TypedValue +floorInput = + ValueIR.Apply intTypeInstance floorRef <| mFloatLiteralOf 2.5 + + +floorRef : ValueIR.TypedValue +floorRef = + ValueIR.Reference + (mFuncTypeOf floatTypeInstance intTypeInstance) + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "floor" ] ) + + +floorExpected : Scala.Value +floorExpected = + sExpCall (sSnowparkRefFuncion "floor") <| floorParams + + +floorParams : List Scala.Value +floorParams = + [ sExpCall (sSnowparkRefFuncion "lit") <| [ sFloatLit 2.5 ] ] + + +modbyInput : ValueIR.TypedValue +modbyInput = + ValueIR.Apply intTypeInstance modbyFunction <| mIntLiteralOf 6 + + +modbyFunction : ValueIR.TypedValue +modbyFunction = + ValueIR.Apply (mFuncTypeOf intTypeInstance intTypeInstance) modbyRef <| mIntLiteralOf 5 + + +modbyRef : ValueIR.TypedValue +modbyRef = + ValueIR.Reference + (mFuncTypeOf intTypeInstance (mFuncTypeOf intTypeInstance intTypeInstance)) + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "mod", "by" ] ) + + +inputOperatorTest : List String -> ValueIR.Value ta (TypeIR.Type ()) +inputOperatorTest operatorName = + ValueIR.Apply + (TypeIR.Reference + () + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) + [] + ) + (ValueIR.Apply + (TypeIR.Function + () + (TypeIR.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) []) + (TypeIR.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) []) + ) + (ValueIR.Reference + (TypeIR.Function + () + (TypeIR.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) []) + (TypeIR.Function () (TypeIR.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) []) (TypeIR.Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "int" ] ) [])) + ) + ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], operatorName ) + ) + (createNumberLiteral 5) + ) + (createNumberLiteral 6) + + +outputOperatorTest : String -> Scala.Value +outputOperatorTest operator = + Scala.BinOp (Scala.Apply (Scala.Ref [ "com", "snowflake", "snowpark", "functions" ] "lit") [ Scala.ArgValue Nothing (Scala.Literal (Scala.IntegerLit 5)) ]) + operator + (Scala.Apply (Scala.Ref [ "com", "snowflake", "snowpark", "functions" ] "lit") [ Scala.ArgValue Nothing (Scala.Literal (Scala.IntegerLit 6)) ]) + + +mapValueListTest : Test +mapValueListTest = + let + emptyContext = + emptyValueMappingContext + + assertAddTest = + test "add" <| + \_ -> + let + ( mapped, _ ) = + mapValue (inputOperatorTest [ "add" ]) emptyContext + in + Expect.equal mapped (outputOperatorTest "+") + + assertSubstractTest = + test "Substract" <| + \_ -> + let + ( mapped, _ ) = + mapValue (inputOperatorTest [ "subtract" ]) emptyContext + in + Expect.equal mapped (outputOperatorTest "-") + + assertMultiplyTest = + test "multiply" <| + \_ -> + let + ( mapped, _ ) = + mapValue (inputOperatorTest [ "multiply" ]) emptyContext + in + Expect.equal mapped (outputOperatorTest "*") + + assertdivideTest = + test "divide" <| + \_ -> + let + ( mapped, _ ) = + mapValue (inputOperatorTest [ "divide" ]) emptyContext + in + Expect.equal mapped (outputOperatorTest "/") + + assertintegerdivideTest = + test "integer divide" <| + \_ -> + let + ( mapped, _ ) = + mapValue (inputOperatorTest [ "integer", "divide" ]) emptyContext + in + Expect.equal mapped (outputOperatorTest "/") + + assertModbyTest = + test "modby test" <| + \_ -> + let + ( mapped, _ ) = + mapValue modbyInput emptyContext + in + Expect.equal mapped (outputOperatorTest "%") + + assertFloorTest = + test "floor test" <| + \_ -> + let + ( mapped, _ ) = + mapValue floorInput emptyContext + in + Expect.equal mapped floorExpected + in + describe "arithmetic operators" + [ assertAddTest + , assertSubstractTest + , assertMultiplyTest + , assertdivideTest + , assertintegerdivideTest + , assertModbyTest + , assertFloorTest + ] diff --git a/tests/Morphir/Snowpark/MappingContextTests.elm b/tests/Morphir/Snowpark/MappingContextTests.elm new file mode 100644 index 000000000..88716ac56 --- /dev/null +++ b/tests/Morphir/Snowpark/MappingContextTests.elm @@ -0,0 +1,353 @@ +module Morphir.Snowpark.MappingContextTests exposing + ( functionClassificationTests + , typeClassificationTests + ) + +import Dict +import Expect +import Morphir.IR.AccessControlled exposing (public) +import Morphir.IR.FQName as FQName +import Morphir.IR.Module exposing (emptyDefinition) +import Morphir.IR.Name as Name +import Morphir.IR.Path as Path +import Morphir.IR.Type as Type exposing (Type(..)) +import Morphir.IR.Value as Value +import Morphir.Snowpark.CommonTestUtils exposing (mListTypeOf) +import Morphir.Snowpark.MappingContext as MappingContext exposing (FunctionClassification(..)) +import Set +import Test exposing (Test, describe, test) + + +floatTypeInstance : Type () +floatTypeInstance = + Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "basics" ] ], [ "float" ] ) [] + + +stringTypeInstance : Type () +stringTypeInstance = + Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) [] + + +refToLocalType : String -> Type () +refToLocalType name = + Reference () (FQName.fromString ("UTest:MyMod:" ++ name) ":") [] + + +testDistributionName = + Path.fromString "UTest" + + +testDistributionPackage = + { modules = + Dict.fromList + [ ( Path.fromString "MyMod" + , public + { emptyDefinition + | types = + Dict.fromList + [ -- A type alias + ( Name.fromString "Price" + , public { doc = "", value = Type.TypeAliasDefinition [ [ "t1" ] ] floatTypeInstance } + ) + , -- A record with simple types + ( Name.fromString "Emp1" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "name", tpe = stringTypeInstance } + , { name = Name.fromString "salary", tpe = floatTypeInstance } + ] + ) + } + ) + , -- A Union type without constructors with parameters + ( Name.fromString "DeptKind" + , public + { doc = "" + , value = + Type.CustomTypeDefinition [] + (public + (Dict.fromList + [ ( Name.fromString "Hr", [] ) + , ( Name.fromString "It", [] ) + ] + ) + ) + } + ) + , -- A Union type with constructors with parameters + ( Name.fromString "FloatOptionType" + , public + { doc = "" + , value = + Type.CustomTypeDefinition [] + (public + (Dict.fromList + [ ( Name.fromString "No", [] ) + , ( Name.fromString "Yes", [ ( [], floatTypeInstance ) ] ) + ] + ) + ) + } + ) + , -- A record with simple types + ( Name.fromString "Emp2" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "name", tpe = stringTypeInstance } + , { name = Name.fromString "salary", tpe = Reference () (FQName.fromString "UTest:MyMod:Price" ":") [] } + , { name = Name.fromString "dept", tpe = Reference () (FQName.fromString "UTest:MyMod:DeptKind" ":") [] } + ] + ) + } + ) + , -- A record with nested types + ( Name.fromString "Dept1" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "name", tpe = stringTypeInstance } + , { name = Name.fromString "head", tpe = Reference () (FQName.fromString "UTest:MyMod:Emp1" ":") [] } + ] + ) + } + ) + , -- A type alias of an alias + ( Name.fromString "LocalPrice" + , public { doc = "", value = Type.TypeAliasDefinition [ [ "t1" ] ] (refToLocalType "Price") } + ) + ] + , values = + Dict.fromList + [ ( Name.fromString "fromBasicTypesToSimpleRecords" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", floatTypeInstance, floatTypeInstance ) ] + , outputType = Reference () (FQName.fromString "UTest:MyMod:Emp2" ":") [] + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + , ( Name.fromString "fromComplexTypesToValues" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", refToLocalType "Dept1", refToLocalType "Dept1" ) ] + , outputType = stringTypeInstance + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + , ( Name.fromString "fromComplexTypesToDataFrames" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", refToLocalType "Dept1", refToLocalType "Dept1" ) ] + , outputType = mListTypeOf (refToLocalType "Emp2") + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + , ( Name.fromString "fromCustomTypesToValues" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", refToLocalType "DeptKind", refToLocalType "DeptKind" ) ] + , outputType = stringTypeInstance + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + , ( Name.fromString "fromAliasedSimpleValuesToSimpleValues" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", refToLocalType "LocalPrice", refToLocalType "LocalPrice" ) ] + , outputType = refToLocalType "Price" + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + , ( Name.fromString "fromDataFramesToSimpleValues" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", mListTypeOf (refToLocalType "Emp2"), mListTypeOf (refToLocalType "Emp2") ) ] + , outputType = floatTypeInstance + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + , ( Name.fromString "fromDataFramesToDataFrames" + , public + { doc = "" + , value = + { inputTypes = [ ( Name.fromString "a", mListTypeOf (refToLocalType "Emp2"), mListTypeOf (refToLocalType "Emp2") ) ] + , outputType = mListTypeOf (refToLocalType "Emp2") + , body = Value.Variable (Type.Unit ()) [ "_" ] -- dummy body + } + } + ) + ] + } + ) + ] + } + + +typeClassificationTests : Test +typeClassificationTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( calculatedContext, _, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + assertCount = + test "Types in context" <| + \_ -> + Expect.equal 7 (Dict.size calculatedContext) + + assertTypeAliasLookup = + test "Type alias lookup" <| + \_ -> + Expect.equal True (MappingContext.isTypeAlias (FQName.fromString "UTest:MyMod:Price" ":") calculatedContext) + + assertNegativeTypeAliasLookup = + test "Type negative alias lookup" <| + \_ -> + Expect.equal False (MappingContext.isTypeAlias (FQName.fromString "UTest:MyMod:Emp1" ":") calculatedContext) + + assertTypeRecordSimpleLookup = + test "Lookup for type with simple types" <| + \_ -> + Expect.equal True (MappingContext.isRecordWithSimpleTypes (FQName.fromString "UTest:MyMod:Emp1" ":") calculatedContext) + + assertTypeRecordSimpleWithAliasesLookup = + test "Lookup for type with simple types with aliases" <| + \_ -> + Expect.equal True (MappingContext.isRecordWithSimpleTypes (FQName.fromString "UTest:MyMod:Emp2" ":") calculatedContext) + + assertNegativeTestOnComplexTypePredicate = + test "Lookup type that should not be classifed as record with complex fields" <| + \_ -> + Expect.equal False (MappingContext.isRecordWithComplexTypes (FQName.fromString "UTest:MyMod:Emp2" ":") calculatedContext) + + assertTypeRecordWithComplexLookup = + test "Lookup type that should be classified as record with complex fields" <| + \_ -> + Expect.equal True (MappingContext.isRecordWithComplexTypes (FQName.fromString "UTest:MyMod:Dept1" ":") calculatedContext) + + assertLookupForUnionTypeWithNames = + test "Lookup type that should be classified as union type without constructors with parameters" <| + \_ -> + Expect.equal True (MappingContext.isUnionTypeWithoutParams (FQName.fromString "UTest:MyMod:DeptKind" ":") calculatedContext) + + assertLookupForUnionTypeWithParameters = + test "Lookup type that should be classified as union type with constructors having parameters" <| + \_ -> + Expect.equal True (MappingContext.isUnionTypeWithParams (FQName.fromString "UTest:MyMod:FloatOptionType" ":") calculatedContext) + in + describe "type classification" + [ assertCount + , assertTypeAliasLookup + , assertNegativeTypeAliasLookup + , assertTypeRecordSimpleLookup + , assertTypeRecordSimpleWithAliasesLookup + , assertNegativeTestOnComplexTypePredicate + , assertTypeRecordWithComplexLookup + , assertLookupForUnionTypeWithNames + , assertLookupForUnionTypeWithParameters + ] + + +functionClassificationTests : Test +functionClassificationTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( _, functionClassificationInfo, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + assertFunctionClassificationForReturningRecords = + test "Lookup function classficiation for simple to record types" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromBasicTypesToSimpleRecords" ":" + in + Expect.equal FromDfValuesToDfValues (MappingContext.getFunctionClassification funcName functionClassificationInfo) + + assertFunctionClassificationForReceivingComplexTypes = + test "Lookup function classification function receiving complex types and returning simple values" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromComplexTypesToValues" ":" + in + Expect.equal FromComplexToValues (MappingContext.getFunctionClassification funcName functionClassificationInfo) + + assertFunctionWithReceivingCustomTypes = + test "Lookup function classficiation function receiving custom types and returning simple values" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromCustomTypesToValues" ":" + in + Expect.equal FromDfValuesToDfValues (MappingContext.getFunctionClassification funcName functionClassificationInfo) + + assertFunctionClassificationOfAliasedSimpleValuesToSimpleValues = + test "Lookup function classification aliased simple values to simple values" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromAliasedSimpleValuesToSimpleValues" ":" + in + Expect.equal FromDfValuesToDfValues (MappingContext.getFunctionClassification funcName functionClassificationInfo) + + assertFunctionClassificationOfComplexTypesToDataFrames = + test "Lookup function classification complex types to dataframes" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromComplexTypesToDataFrames" ":" + in + Expect.equal FromComplexValuesToDataFrames (MappingContext.getFunctionClassification funcName functionClassificationInfo) + + assertFunctionClassificationOfDataFramesToSimpleValues = + test "Lookup function classification dataframes to simple values" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromDataFramesToSimpleValues" ":" + in + Expect.equal FromDataFramesToValues (MappingContext.getFunctionClassification funcName functionClassificationInfo) + + assertFunctionClassificationOfDataFramesToDataFrames = + test "Lookup function classification dataframes to dataframes" <| + \_ -> + let + funcName = + FQName.fromString "UTest:MyMod:fromDataFramesToDataFrames" ":" + in + Expect.equal FromDataFramesToDataFrames (MappingContext.getFunctionClassification funcName functionClassificationInfo) + in + describe "function classification" + [ assertFunctionClassificationForReturningRecords + , assertFunctionClassificationForReceivingComplexTypes + , assertFunctionWithReceivingCustomTypes + , assertFunctionClassificationOfAliasedSimpleValuesToSimpleValues + , assertFunctionClassificationOfComplexTypesToDataFrames + , assertFunctionClassificationOfDataFramesToSimpleValues + , assertFunctionClassificationOfDataFramesToDataFrames + ] diff --git a/tests/Morphir/Snowpark/PatternMatchTests.elm b/tests/Morphir/Snowpark/PatternMatchTests.elm new file mode 100644 index 000000000..b399f7990 --- /dev/null +++ b/tests/Morphir/Snowpark/PatternMatchTests.elm @@ -0,0 +1,514 @@ +module Morphir.Snowpark.PatternMatchTests exposing (caseOfGenTests) + +import Dict exposing (Dict(..)) +import Expect +import Morphir.IR.FQName as FQName +import Morphir.IR.Literal as Literal +import Morphir.IR.Type as Type +import Morphir.IR.Value as Value +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.CommonTestUtils + exposing + ( floatTypeInstance + , intTypeInstance + , mIdOf + , mIntLiteralOf + , mMaybeTypeOf + , mStringLiteralOf + , sCall + , sDot + , sExpCall + , sIntLit + , sLit + , sVar + , stringTypeInstance + , testDistributionName + , testDistributionPackage + ) +import Morphir.Snowpark.Constants exposing (applySnowparkFunc) +import Morphir.Snowpark.MapExpressionsToDataFrameOperations exposing (mapValue) +import Morphir.Snowpark.MapFunctionsMapping exposing (maybeFunctionName) +import Morphir.Snowpark.MappingContext as MappingContext exposing (emptyValueMappingContext) +import Set +import Test exposing (Test, describe, test) + + +str : Type.Type () +str = + stringTypeInstance + + +aLit : Literal.Literal +aLit = + Literal.stringLiteral "A" + + +a2Lit : Literal.Literal +a2Lit = + Literal.stringLiteral "a" + + +mCaseOf : Value.TypedValue -> List ( Value.Pattern (Type.Type ()), Value.TypedValue ) -> Value.TypedValue +mCaseOf expr cases = + let + returnType = + cases + |> List.head + |> Maybe.map (\( _, firstValue ) -> Value.valueAttribute firstValue) + |> Maybe.withDefault (Type.Unit ()) + in + Value.PatternMatch returnType expr cases + + +mTuple2Of : Value.TypedValue -> Value.TypedValue -> Value.TypedValue +mTuple2Of value1 value2 = + let + tupleType = + Type.Tuple () [ Value.valueAttribute value1, Value.valueAttribute value2 ] + in + Value.Tuple tupleType [ value1, value2 ] + + +caseOfGenTests : Test +caseOfGenTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + ( calculatedContext, _, _ ) = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + cases = + [ ( Value.LiteralPattern str aLit, Value.Literal str a2Lit ) + , ( Value.WildcardPattern str, Value.Literal str (Literal.stringLiteral "D") ) + ] + + inputCase = + Value.PatternMatch stringTypeInstance (Value.Literal str (Literal.stringLiteral "X")) cases + + ctx = + { emptyValueMappingContext | typesContextInfo = calculatedContext } + + ( mappedCase, _ ) = + mapValue inputCase ctx + + mappedCaseParts = + case mappedCase of + Scala.Apply (Scala.Select (Scala.Apply (Scala.Ref _ "when") [ Scala.ArgValue _ (Scala.BinOp left1 "===" right1), Scala.ArgValue _ result1 ]) "otherwise") [ Scala.ArgValue _ result2 ] -> + [ left1, right1, result1, result2 ] + + _ -> + [] + + assertCaseWithLiterals = + test "Convert case of with literals" <| + \_ -> + Expect.equal + [ applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit "X") ] + , applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit "A") ] + , applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit "a") ] + , applySnowparkFunc "lit" [ Scala.Literal (Scala.StringLit "D") ] + ] + mappedCaseParts + + assertCaseWithMaybeFullCases = + test "Generate case of with Maybe type with both constructors" <| + \_ -> + let + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] (mMaybeTypeOf stringTypeInstance)) + [ ( Value.ConstructorPattern + (mMaybeTypeOf stringTypeInstance) + (maybeFunctionName [ "just" ]) + [ Value.AsPattern stringTypeInstance (Value.WildcardPattern stringTypeInstance) [ "t" ] ] + , mIdOf [ "t" ] stringTypeInstance + ) + , ( Value.ConstructorPattern (mMaybeTypeOf stringTypeInstance) (maybeFunctionName [ "nothing" ]) [] + , mStringLiteralOf "DEFAULT" + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( applySnowparkFunc "when" [ sDot (sVar "x") "is_not_null", sVar "x" ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sLit "DEFAULT" ] ] + in + Expect.equal mapped expected + + assertCaseWithMaybeWithDefault = + test "Generate case of with Maybe type with default case" <| + \_ -> + let + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] (mMaybeTypeOf stringTypeInstance)) + [ ( Value.ConstructorPattern + (mMaybeTypeOf stringTypeInstance) + (maybeFunctionName [ "just" ]) + [ Value.AsPattern stringTypeInstance (Value.WildcardPattern stringTypeInstance) [ "t" ] ] + , mIdOf [ "t" ] stringTypeInstance + ) + , ( Value.WildcardPattern (mMaybeTypeOf stringTypeInstance) + , mStringLiteralOf "DEFAULT" + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( applySnowparkFunc "when" [ sDot (sVar "x") "is_not_null", sVar "x" ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sLit "DEFAULT" ] ] + in + Expect.equal mapped expected + + assertCaseWithMaybeWithDefaultAndNothing = + test "Generate case of with Maybe type with Nothing and default case" <| + \_ -> + let + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] (mMaybeTypeOf stringTypeInstance)) + [ ( Value.ConstructorPattern (mMaybeTypeOf stringTypeInstance) (maybeFunctionName [ "nothing" ]) [] + , mStringLiteralOf "DEFAULT1" + ) + , ( Value.WildcardPattern (mMaybeTypeOf stringTypeInstance) + , mStringLiteralOf "DEFAULT2" + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( applySnowparkFunc "when" [ sDot (sVar "x") "is_not_null", applySnowparkFunc "lit" [ sLit "DEFAULT2" ] ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sLit "DEFAULT1" ] ] + in + Expect.equal mapped expected + + assertCaseWithTupleAndLiteralTuple = + test "Generate case of with tuple and literal tuple as expression" <| + \_ -> + let + innerJustPattern = + Value.ConstructorPattern + (mMaybeTypeOf stringTypeInstance) + (maybeFunctionName [ "just" ]) + [ Value.AsPattern stringTypeInstance (Value.WildcardPattern stringTypeInstance) [ "t" ] ] + + inputCaseExpr = + mCaseOf (mTuple2Of (mIdOf [ "x" ] (mMaybeTypeOf stringTypeInstance)) (mIdOf [ "y" ] (mMaybeTypeOf floatTypeInstance))) + [ ( Value.TuplePattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + [ innerJustPattern, Value.WildcardPattern floatTypeInstance ] + , mIdOf [ "t" ] stringTypeInstance + ) + , ( Value.TuplePattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + [ Value.WildcardPattern stringTypeInstance, innerJustPattern ] + , mStringLiteralOf "DEFAULT1" + ) + , ( Value.WildcardPattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + , mStringLiteralOf "DEFAULT" + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( sCall + ( applySnowparkFunc "when" [ sDot (sVar "x") "is_not_null", sVar "x" ] + , "when" + ) + [ sDot (sVar "y") "is_not_null", applySnowparkFunc "lit" [ sLit "DEFAULT1" ] ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sLit "DEFAULT" ] ] + in + Expect.equal mapped expected + + assertCaseWithTupleAndLiteralTupleWithTupleVar = + test "Generate case of with tuple and tuple variable as expression" <| + \_ -> + let + innerJustPattern = + Value.ConstructorPattern + (mMaybeTypeOf stringTypeInstance) + (maybeFunctionName [ "just" ]) + [ Value.AsPattern stringTypeInstance (Value.WildcardPattern stringTypeInstance) [ "t" ] ] + + inputCaseExpr = + mCaseOf (mIdOf [ "tVar" ] (Type.Tuple () [ stringTypeInstance, floatTypeInstance ])) + [ ( Value.TuplePattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + [ innerJustPattern, Value.WildcardPattern floatTypeInstance ] + , mIdOf [ "t" ] stringTypeInstance + ) + , ( Value.TuplePattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + [ Value.WildcardPattern stringTypeInstance, innerJustPattern ] + , mStringLiteralOf "DEFAULT1" + ) + , ( Value.WildcardPattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + , mStringLiteralOf "DEFAULT" + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( sCall + ( applySnowparkFunc "when" [ sDot (sExpCall (sVar "tVar") [ sIntLit 0 ]) "is_not_null", sExpCall (sVar "tVar") [ sIntLit 0 ] ] + , "when" + ) + [ sDot (sExpCall (sVar "tVar") [ sIntLit 1 ]) "is_not_null", applySnowparkFunc "lit" [ sLit "DEFAULT1" ] ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sLit "DEFAULT" ] ] + in + Expect.equal mapped expected + + assertCaseWithTupleAndLiteralTupleWithoutDefault = + test "Generate case of with tuple and literal tuple as expression without default case" <| + \_ -> + let + innerJustPattern = + Value.ConstructorPattern + (mMaybeTypeOf stringTypeInstance) + (maybeFunctionName [ "just" ]) + [ Value.AsPattern stringTypeInstance (Value.WildcardPattern stringTypeInstance) [ "t" ] ] + + inputCaseExpr = + mCaseOf (mTuple2Of (mIdOf [ "x" ] (mMaybeTypeOf stringTypeInstance)) (mIdOf [ "y" ] (mMaybeTypeOf floatTypeInstance))) + [ ( Value.TuplePattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + [ innerJustPattern, Value.WildcardPattern floatTypeInstance ] + , mIdOf [ "t" ] stringTypeInstance + ) + , ( Value.TuplePattern (Type.Tuple () [ stringTypeInstance, floatTypeInstance ]) + [ Value.WildcardPattern stringTypeInstance, innerJustPattern ] + , mStringLiteralOf "DEFAULT1" + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( applySnowparkFunc "when" [ sDot (sVar "x") "is_not_null", sVar "x" ] + , "when" + ) + [ sDot (sVar "y") "is_not_null", applySnowparkFunc "lit" [ sLit "DEFAULT1" ] ] + in + Expect.equal mapped expected + + assertCaseWithCustomTypeWithParameters = + test "Generate case of with Custom type with parameters" <| + \_ -> + let + timeRangeType = + Type.Reference () (FQName.fqn "UTest" "MyMod" "TimeRange") [] + + myModName name = + FQName.fqn "UTest" "MyMod" name + + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] timeRangeType) + [ ( Value.ConstructorPattern timeRangeType + (myModName "Seconds") + [ Value.AsPattern intTypeInstance (Value.WildcardPattern intTypeInstance) [ "t" ] ] + , mIdOf [ "t" ] intTypeInstance + ) + , ( Value.ConstructorPattern timeRangeType + (myModName "MinutesAndSeconds") + [ Value.wildcardPattern intTypeInstance, Value.AsPattern intTypeInstance (Value.WildcardPattern intTypeInstance) [ "t" ] ] + , mIdOf [ "t" ] intTypeInstance + ) + , ( Value.ConstructorPattern timeRangeType (myModName "Zero") [] + , mIntLiteralOf 100 + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( sCall + ( applySnowparkFunc "when" + [ Scala.BinOp (sExpCall (sVar "x") [ sLit "__tag" ]) "===" (applySnowparkFunc "lit" [ sLit "Seconds" ]) + , sExpCall (sVar "x") [ sLit "field0" ] + ] + , "when" + ) + [ Scala.BinOp (sExpCall (sVar "x") [ sLit "__tag" ]) "===" (applySnowparkFunc "lit" [ sLit "MinutesAndSeconds" ]) + , sExpCall (sVar "x") [ sLit "field1" ] + ] + , "when" + ) + [ Scala.BinOp (sExpCall (sVar "x") [ sLit "__tag" ]) "===" (applySnowparkFunc "lit" [ sLit "Zero" ]) + , applySnowparkFunc "lit" [ sIntLit 100 ] + ] + in + Expect.equal mapped expected + + assertCaseWithCustomTypeWithParametersAndDefault = + test "Generate case of with Custom type with parameters and default value" <| + \_ -> + let + timeRangeType = + Type.Reference () (FQName.fqn "UTest" "MyMod" "TimeRange") [] + + myModName name = + FQName.fqn "UTest" "MyMod" name + + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] timeRangeType) + [ ( Value.ConstructorPattern timeRangeType + (myModName "Seconds") + [ Value.AsPattern intTypeInstance (Value.WildcardPattern intTypeInstance) [ "t" ] ] + , mIdOf [ "t" ] intTypeInstance + ) + , ( Value.ConstructorPattern timeRangeType + (myModName "MinutesAndSeconds") + [ Value.wildcardPattern intTypeInstance, Value.AsPattern intTypeInstance (Value.WildcardPattern intTypeInstance) [ "t" ] ] + , mIdOf [ "t" ] intTypeInstance + ) + , ( Value.WildcardPattern timeRangeType + , mIntLiteralOf 101 + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( sCall + ( applySnowparkFunc "when" + [ Scala.BinOp (sExpCall (sVar "x") [ sLit "__tag" ]) "===" (applySnowparkFunc "lit" [ sLit "Seconds" ]) + , sExpCall (sVar "x") [ sLit "field0" ] + ] + , "when" + ) + [ Scala.BinOp (sExpCall (sVar "x") [ sLit "__tag" ]) "===" (applySnowparkFunc "lit" [ sLit "MinutesAndSeconds" ]) + , sExpCall (sVar "x") [ sLit "field1" ] + ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sIntLit 101 ] ] + in + Expect.equal mapped expected + + assertCaseWithCustomTypeWithoutParameters = + test "Generate case of with Custom type without parameters" <| + \_ -> + let + deptKindType = + Type.Reference () (FQName.fqn "UTest" "MyMod" "DeptKind") [] + + myModName name = + FQName.fqn "UTest" "MyMod" name + + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] deptKindType) + [ ( Value.ConstructorPattern deptKindType (myModName "Hr") [] + , mIntLiteralOf 10 + ) + , ( Value.ConstructorPattern deptKindType (myModName "It") [] + , mIntLiteralOf 20 + ) + , ( Value.ConstructorPattern deptKindType (myModName "Logic") [] + , mIntLiteralOf 30 + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( sCall + ( applySnowparkFunc "when" + [ Scala.BinOp (sVar "x") "===" (Scala.Ref [ "utest", "MyMod", "DeptKind" ] "Hr") + , applySnowparkFunc "lit" [ sIntLit 10 ] + ] + , "when" + ) + [ Scala.BinOp (sVar "x") "===" (Scala.Ref [ "utest", "MyMod", "DeptKind" ] "It") + , applySnowparkFunc "lit" [ sIntLit 20 ] + ] + , "when" + ) + [ Scala.BinOp (sVar "x") "===" (Scala.Ref [ "utest", "MyMod", "DeptKind" ] "Logic") + , applySnowparkFunc "lit" [ sIntLit 30 ] + ] + in + Expect.equal mapped expected + + assertCaseWithCustomTypeWithoutParametersWithDefault = + test "Generate case of with Custom type without parameters with default case" <| + \_ -> + let + deptKindType = + Type.Reference () (FQName.fqn "UTest" "MyMod" "DeptKind") [] + + myModName name = + FQName.fqn "UTest" "MyMod" name + + inputCaseExpr = + mCaseOf (mIdOf [ "x" ] deptKindType) + [ ( Value.ConstructorPattern deptKindType (myModName "Hr") [] + , mIntLiteralOf 10 + ) + , ( Value.ConstructorPattern deptKindType (myModName "It") [] + , mIntLiteralOf 20 + ) + , ( Value.WildcardPattern deptKindType + , mIntLiteralOf 30 + ) + ] + + ( mapped, _ ) = + mapValue inputCaseExpr ctx + + expected = + sCall + ( sCall + ( applySnowparkFunc "when" + [ Scala.BinOp (sVar "x") "===" (Scala.Ref [ "utest", "MyMod", "DeptKind" ] "Hr") + , applySnowparkFunc "lit" [ sIntLit 10 ] + ] + , "when" + ) + [ Scala.BinOp (sVar "x") "===" (Scala.Ref [ "utest", "MyMod", "DeptKind" ] "It") + , applySnowparkFunc "lit" [ sIntLit 20 ] + ] + , "otherwise" + ) + [ applySnowparkFunc "lit" [ sIntLit 30 ] ] + in + Expect.equal mapped expected + in + describe "PatternConversionTests" + [ assertCaseWithLiterals + , assertCaseWithMaybeFullCases + , assertCaseWithMaybeWithDefault + , assertCaseWithMaybeWithDefaultAndNothing + , assertCaseWithTupleAndLiteralTuple + , assertCaseWithTupleAndLiteralTupleWithTupleVar + , assertCaseWithTupleAndLiteralTupleWithoutDefault + , assertCaseWithCustomTypeWithParameters + , assertCaseWithCustomTypeWithParametersAndDefault + , assertCaseWithCustomTypeWithoutParameters + , assertCaseWithCustomTypeWithoutParametersWithDefault + ] diff --git a/tests/Morphir/Snowpark/RecordWrapperGenerationTests.elm b/tests/Morphir/Snowpark/RecordWrapperGenerationTests.elm new file mode 100644 index 000000000..5e463f796 --- /dev/null +++ b/tests/Morphir/Snowpark/RecordWrapperGenerationTests.elm @@ -0,0 +1,93 @@ +module Morphir.Snowpark.RecordWrapperGenerationTests exposing (..) + +import Dict +import Expect +import Morphir.IR.AccessControlled exposing (public) +import Morphir.IR.Module exposing (emptyDefinition) +import Morphir.IR.Name as Name +import Morphir.IR.Path as Path +import Morphir.IR.Type as Type exposing (Type(..)) +import Morphir.Scala.AST as Scala +import Morphir.Snowpark.MappingContext as MappingContext +import Morphir.Snowpark.RecordWrapperGenerator as RecordWrapperGenerator +import Set +import Test exposing (Test, describe, test) + + +stringTypeInstance : Type () +stringTypeInstance = + Reference () ( [ [ "morphir" ], [ "s", "d", "k" ] ], [ [ "string" ] ], [ "string" ] ) [] + + +testDistributionName = + Path.fromString "UTest" + + +typesDict = + Dict.fromList + [ -- A record with simple types + ( Name.fromString "Emp1" + , public + { doc = "" + , value = + Type.TypeAliasDefinition [] + (Type.Record () + [ { name = Name.fromString "firstname", tpe = stringTypeInstance } + , { name = Name.fromString "lastname", tpe = stringTypeInstance } + ] + ) + } + ) + ] + + +testDistributionPackage = + { modules = + Dict.fromList + [ ( Path.fromString "MyMod" + , public { emptyDefinition | types = typesDict } + ) + ] + } + + +typeClassificationTests : Test +typeClassificationTests = + let + customizationOptions = + { functionsToInline = Set.empty, functionsToCache = Set.empty } + + calculatedContext = + MappingContext.processDistributionModules testDistributionName testDistributionPackage customizationOptions + + firstModule = + Dict.get [ Name.fromString "MyMod" ] testDistributionPackage.modules |> Maybe.map (\access -> access.value) + + assertItCreatedWrapper = + test "Wrapper creation" <| + \_ -> + let + generationResult = + firstModule + |> Maybe.map (\mod -> RecordWrapperGenerator.generateRecordWrappers testDistributionName (Path.fromString "MyMod") calculatedContext mod.types) + |> Maybe.map (\scalaElementList -> scalaElementList |> List.map stringFromScalaTypeDefinition) + |> Maybe.withDefault [] + in + Expect.equal [ "Trait:Emp1:2", "Object:Emp1:5", "Class:Emp1Wrapper:2" ] generationResult + in + describe "resolveTNam" + [ assertItCreatedWrapper + ] + + +stringFromScalaTypeDefinition : Scala.Documented (Scala.Annotated Scala.TypeDecl) -> String +stringFromScalaTypeDefinition scalaElement = + case scalaElement.value.value of + Scala.Object { name, members } -> + "Object:" ++ name ++ ":" ++ (members |> List.length |> String.fromInt) + + Scala.Trait { name, members } -> + "Trait:" ++ name ++ ":" ++ (members |> List.length |> String.fromInt) + + Scala.Class { name, members } -> + "Class:" ++ name ++ ":" ++ (members |> List.length |> String.fromInt)