diff --git a/purescript/spago.lock b/purescript/spago.lock index 2b190c8..5f9e1dd 100644 --- a/purescript/spago.lock +++ b/purescript/spago.lock @@ -6,6 +6,7 @@ workspace: - argonaut - argonaut-generic - console + - debug - effect - node-process - prelude @@ -31,6 +32,7 @@ workspace: - contravariant - control - datetime + - debug - distributive - effect - either @@ -763,6 +765,13 @@ packages: - partial - prelude - tuples + debug: + type: registry + version: 6.0.2 + integrity: sha256-vmkYFuXYuELBzeauvgHG6E6Kf/Hp1dAnxwE9ByHfwSg= + dependencies: + - functions + - prelude distributive: type: registry version: 6.0.0 diff --git a/purescript/spago.yaml b/purescript/spago.yaml index dd2f809..1f73517 100644 --- a/purescript/spago.yaml +++ b/purescript/spago.yaml @@ -4,6 +4,7 @@ package: - argonaut - argonaut-generic - console + - debug - effect - node-process - prelude diff --git a/purescript/src/Oclis/Executor.purs b/purescript/src/Oclis/Executor.purs index 3cbeed6..0c1fd97 100644 --- a/purescript/src/Oclis/Executor.purs +++ b/purescript/src/Oclis/Executor.purs @@ -4,14 +4,10 @@ module Oclis where -import Oclis.Types - import Prelude (Unit, bind, discard, pure, unit, (#), ($), (-), (<>), (>), (||)) import Ansi.Codes (Color(..)) import Ansi.Output (withGraphics, foreground) -import Oclis.Parser (tokensToCliArguments) -import Oclis.Tokenizer (tokenizeCliArguments) import Data.Argonaut.Decode (decodeJson) import Data.Argonaut.Decode.Error (printJsonDecodeError) import Data.Argonaut.Parser (jsonParser) @@ -25,6 +21,11 @@ import Effect (Effect) import Effect.Class.Console (log, error) import Node.Process (argv, setExitCode) +import Oclis.Parser (tokensToCliArguments) +import Oclis.SpecEmbed (fileContent) +import Oclis.Tokenizer (tokenizeCliArguments) +import Oclis.Types + -- TODO: Automatically disable colors if not supported makeRed :: String -> String makeRed str = @@ -144,11 +145,34 @@ repeatString :: String -> Int -> String repeatString str n = fold $ replicate n str -callCliApp +-- | Convenience function to call the CLI app with the default spec and args. +-- | Use `callCliAppWith`` if you want to provide your own values. +callCliApp :: (ExecutorContext -> Effect (Result String Unit)) -> Effect Unit +callCliApp executor = + case parseCliSpec fileContent of + Error errMsg -> do + error $ + "ERROR:\n" + <> "The auto-generated CLI specification in SpecEmbed.purs " + <> "could not be parsed.\n" + <> "This should not be possible!\n" + <> "Please make sure you didn't accidentally modify any Oclis files\n" + <> "and report following error at " + <> "https://github.com/Airsequel/Oclis/issues/new:\n" + <> "\n" + <> errMsg + setExitCode 1 + Ok cliSpec -> do + arguments <- argv + _ <- callCliAppWith cliSpec executor arguments + pure unit + +callCliAppWith :: Oclis -> (ExecutorContext -> Effect (Result String Unit)) + -> Array String -> Effect (Result String Unit) -callCliApp cliSpec@(Oclis cliSpecRaw) executor = do +callCliAppWith cliSpec@(Oclis cliSpecRaw) executor arguments = do let lengthLongestCmd :: Int lengthLongestCmd = @@ -184,8 +208,6 @@ callCliApp cliSpec@(Oclis cliSpecRaw) executor = do ) ) - arguments <- argv - let argsNoInterpreter = arguments # drop 1 -- Drop "node" cliArgsMb = diff --git a/purescript/src/Oclis/SpecEmbed.purs b/purescript/src/Oclis/SpecEmbed.purs new file mode 100644 index 0000000..82c2397 --- /dev/null +++ b/purescript/src/Oclis/SpecEmbed.purs @@ -0,0 +1,14 @@ +-- | This file exists only for testing purposes. +-- | The actual implementation in the user's project +-- | is generated by the `oclis build` command. + +module Oclis.SpecEmbed where + +fileContent :: String +fileContent = + """ + { + "name": "placeholder", + "description": "This is a placeholder command" + } + """ diff --git a/purescript/test/Executor.purs b/purescript/test/Executor.purs index 570e816..5a28bc8 100644 --- a/purescript/test/Executor.purs +++ b/purescript/test/Executor.purs @@ -9,7 +9,7 @@ import Effect.Class (liftEffect) import Test.Spec (Spec, describe, it) import Test.Spec.Assertions (fail, shouldEqual, shouldReturn) -import Oclis (callCommand) +import Oclis (callCliApp, callCommand) import Oclis.Parser (tokensToCliArguments) import Oclis.Tokenizer (tokenizeCliArguments) import Oclis.Types (CliArgPrim(..), CliArgument(..), Oclis(..), emptyCliSpecRaw) @@ -17,6 +17,16 @@ import Oclis.Types (CliArgPrim(..), CliArgument(..), Oclis(..), emptyCliSpecRaw) tests :: Spec Unit tests = describe "Execution" do + it "executes a command with included spec" do + let + executor context = do + context.command `shouldEqual` Nothing + context.usageString `shouldEqual` "xxx" + context.arguments `shouldEqual` [] + pure $ Ok unit + + liftEffect (callCliApp executor) `shouldReturn` unit + describe "Help" do let cliSpec = Oclis emptyCliSpecRaw @@ -65,12 +75,12 @@ tests = cliSpec = Oclis emptyCliSpecRaw usageString = "Irrelevant" executor context = do - context.command `shouldEqual` Just "help" + context.command `shouldEqual` Just "version" context.usageString `shouldEqual` usageString context.arguments `shouldEqual` [] pure $ Ok unit - it "shows help output for -v" do + it "shows version output for -v" do let toolArgs = [ "git", "-v" ] tokens = tokenizeCliArguments toolArgs @@ -81,7 +91,7 @@ tests = liftEffect (callCommand cliSpec usageString cliArgs executor) `shouldReturn` (Ok unit) - it "shows help output for --version" do + it "shows version output for --version" do let toolArgs = [ "git", "--version" ] tokens = tokenizeCliArguments toolArgs @@ -92,9 +102,9 @@ tests = liftEffect (callCommand cliSpec usageString cliArgs executor) `shouldReturn` (Ok unit) - it "shows help output for `help`" do + it "shows version output for `version`" do let - toolArgs = [ "git", "help" ] + toolArgs = [ "git", "version" ] tokens = tokenizeCliArguments toolArgs case tokensToCliArguments cliSpec tokens of