Created
October 12, 2022 15:00
-
-
Save AngelMunoz/bfb1531ffb8a98abe10c98b06bb77dea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Commands = | |
open FSharp.SystemCommandLine | |
open FSharp.SystemCommandLine.Aliases | |
type RunConfiguration with | |
static member FromString(value: string) = | |
match value.ToLowerInvariant() with | |
| "production" | |
| "prod" -> Configuration.Production | |
| "development" | |
| "dev" | |
| _ -> Configuration.Development | |
type Init with | |
static member FromString(value: string) = | |
match value.ToLowerInvariant() with | |
| "full" -> Init.Full | |
| "simple" | |
| _ -> Init.Simple | |
[<AutoOpen>] | |
module Inputs = | |
open System.CommandLine | |
type Input with | |
static member OptionWithStrings | |
( | |
aliases: string seq, | |
values: string seq, | |
defaultValue: string, | |
?description | |
) = | |
Opt<string>( | |
aliases |> Array.ofSeq, | |
getDefaultValue = (fun _ -> defaultValue), | |
?description = description | |
) | |
.FromAmong(values |> Array.ofSeq) | |
|> HandlerInput.OfOption | |
static member ArgumentWithStrings | |
( | |
name: string, | |
defaultValue: string, | |
values: string seq, | |
?description | |
) = | |
Arg<string>( | |
name, | |
getDefaultValue = (fun _ -> defaultValue), | |
?description = description | |
) | |
.FromAmong(values |> Array.ofSeq) | |
|> HandlerInput.OfArgument | |
let modeArg = | |
Input.ArgumentWithStrings( | |
"mode", | |
"dev", | |
[ "development"; "dev"; "prod"; "production" ], | |
"Use Dev or Production dependencies when running, defaults to development" | |
) | |
let serveCmd = | |
let port = | |
Input.OptionMaybe<int>( | |
[ "--port"; "-p" ], | |
"Port where the application starts" | |
) | |
let host = | |
Input.OptionMaybe<string>( | |
[ "--host" ], | |
"network ip address where the application will run" | |
) | |
let ssl = Input.OptionMaybe<bool>([ "--ssl" ], "Run dev server with SSL") | |
let buildArgs | |
( | |
mode: string, | |
port: int option, | |
host: string option, | |
ssl: bool option | |
) : ServeOptions = | |
{ mode = Configuration.FromString mode | |
port = port |> Option.defaultValue 7331 | |
host = host |> Option.defaultValue "127.0.0.1" | |
ssl = ssl |> Option.defaultValue false } | |
command "serve" { | |
description "Starts a development server for single page applications" | |
inputs (modeArg, port, host, ssl) | |
setHandler (buildArgs >> Handlers.handleServe) | |
} | |
let buildCmd = | |
let buildArgs (mode: string) : BuildOptions = | |
{ mode = Configuration.FromString mode } | |
command "build" { | |
description "Builds the SPA application for distribution" | |
inputs modeArg | |
setHandler (buildArgs >> Handlers.runBuild) | |
} | |
let initCmd = | |
let mode = | |
Input.ArgumentWithStrings( | |
"mode", | |
"simple", | |
[ "simple"; "full" ], | |
"Selects if we are initializing a project, or perla itself" | |
) | |
let path = | |
Input.ArgumentMaybe<System.IO.DirectoryInfo>( | |
"path", | |
"Choose what directory to initialize" | |
) | |
let yes = Input.ArgumentMaybe<bool>("yes", "Accept all of the prompts") | |
let fable = | |
Input.OptionMaybe<bool>( | |
[ "--with-fable"; "-wf" ], | |
"The project will use fable" | |
) | |
let buildArgs | |
( | |
mode: string, | |
path: System.IO.DirectoryInfo option, | |
yes: bool option, | |
fable: bool option | |
) : InitOptions = | |
{ mode = Init.FromString mode | |
path = | |
path | |
|> Option.map (fun d -> d.FullName) | |
|> Option.defaultWith (fun _ -> System.IO.Path.GetFullPath "./") | |
yes = yes |> Option.defaultValue false | |
useFable = fable |> Option.defaultValue false } | |
command "init" { | |
description "Initialized a given directory or perla itself" | |
inputs (mode, path, yes, fable) | |
setHandler (buildArgs >> Handlers.runInit) | |
} | |
let searchPackagesCmd = | |
let package = | |
Input.Argument( | |
"package", | |
"The package you want to search for in the skypack api" | |
) | |
let page = | |
Input.ArgumentMaybe( | |
"page", | |
"change the page number in the search results" | |
) | |
let buildArgs (package: string, page: int option) : SearchOptions = | |
{ package = package | |
page = page |> Option.defaultValue 1 } | |
command "search" { | |
description | |
"Search a pacakge name in the skypack api, this will bring potential results" | |
inputs (package, page) | |
setHandler (buildArgs >> Handlers.runSearch) | |
} | |
let showPackageCmd = | |
let package = | |
Input.Argument( | |
"package", | |
"The package you want to search for in the skypack api" | |
) | |
let buildArgs (package: string) : ShowPackageOptions = { package = package } | |
command "show" { | |
description | |
"Shows information about a package if the name matches an existing one" | |
inputs package | |
setHandler (buildArgs >> Handlers.runShow) | |
} | |
let removePackageCmd = | |
let package = | |
Input.Argument( | |
"package", | |
"The package you want to search for in the skypack api" | |
) | |
let alias = | |
Input.OptionMaybe( | |
[ "--alias"; "-a" ], | |
"the alias of the package if you added one" | |
) | |
let buildArgs | |
( | |
package: string, | |
alias: string option | |
) : RemovePackageOptions = | |
{ package = package; alias = alias } | |
command "remove" { | |
description "removes a package from the " | |
inputs (package, alias) | |
setHandler (buildArgs >> Handlers.runRemove) | |
} | |
let addPacakgeCmd = | |
let package = | |
Input.Argument( | |
"package", | |
"The package you want to search for in the skypack api" | |
) | |
let version = | |
Input.ArgumentMaybe( | |
"version", | |
"The version of the package you want to use, it defaults to latest" | |
) | |
let source = | |
Input.OptionWithStrings( | |
[ "--source"; "-s" ], | |
[ "jspm"; "skypack"; "unpkg"; "jsdelivr"; "jspm.system" ], | |
"jspm", | |
"CDN that will be used to fetch dependencies from" | |
) | |
let dev = | |
Input.OptionMaybe( | |
[ "--dev"; "--development"; "-d" ], | |
"Adds this dependency to the dev dependencies" | |
) | |
let alias = | |
Input.OptionMaybe( | |
[ "--alias"; "-a" ], | |
"the alias of the package if you added one" | |
) | |
let buildArgs | |
( | |
package: string, | |
version: string option, | |
source: string, | |
dev: bool option, | |
alias: string option | |
) : AddPackageOptions = | |
{ package = package | |
version = version |> Option.defaultValue "latest" | |
source = Provider.FromString source | |
mode = | |
dev | |
|> Option.map (fun dev -> | |
if dev then | |
Configuration.Development | |
else | |
Configuration.Production) | |
|> Option.defaultValue Configuration.Production | |
alias = alias } | |
command "add" { | |
description | |
"Shows information about a package if the name matches an existing one" | |
inputs (package, version, source, dev, alias) | |
setHandler (buildArgs >> Handlers.runAdd) | |
} | |
let listCmd = | |
let asNpm = | |
Input.OptionMaybe( | |
[ "--npm"; "--as-package-json"; "-j" ], | |
"Show the packages simlar to npm's package.json" | |
) | |
let buildArgs (asNpm: bool option) : ListPackagesOptions = | |
{ format = | |
asNpm | |
|> Option.map (fun asNpm -> | |
if asNpm then | |
ListFormat.PackageJson | |
else | |
ListFormat.HumanReadable) | |
|> Option.defaultValue ListFormat.HumanReadable } | |
command "list" { | |
description | |
"Lists the current dependencies in a table or an npm style json string" | |
inputs asNpm | |
setHandler (buildArgs >> Handlers.runList) | |
} | |
let restoreCmd = | |
let source = | |
Input.OptionWithStrings( | |
[ "--source"; "-s" ], | |
[ "jspm"; "skypack"; "unpkg"; "jsdelivr"; "jspm.system" ], | |
"jspm", | |
"CDN that will be used to fetch dependencies from" | |
) | |
let mode = | |
Input.OptionWithStrings( | |
[ "--mode"; "-m" ], | |
[ "dev"; "development"; "prod"; "production" ], | |
"production", | |
"Restore Dependencies based on the mode to run" | |
) | |
let buildArgs (source: string, mode: string) : RestoreOptions = | |
{ source = Provider.FromString source | |
mode = Configuration.FromString mode } | |
command "restore" { | |
description | |
"Restore the import map based on the selected mode, defaults to production" | |
inputs (source, mode) | |
setHandler (buildArgs >> Handlers.runRestore) | |
} | |
let addTemplateCmd, updateTemplateCmd = | |
let repoName = | |
Input.Argument( | |
"templateRepositoryName", | |
"The User/repository name combination" | |
) | |
let branch = | |
Input.Argument("banch", "Whch branch to pick the template from") | |
let yes = Input.OptionMaybe([ "--yes"; "--continue"; "-y" ], "skip prompts") | |
let buildArgs | |
( | |
name: string, | |
branch: string, | |
yes: bool option | |
) : TemplateRepositoryOptions = | |
{ fullRepositoryName = name | |
branch = branch | |
yes = yes |> Option.defaultValue false } | |
let add = | |
command "templates:add" { | |
description "Adds a new template from a particular repository" | |
inputs (repoName, branch, yes) | |
setHandler (buildArgs >> Handlers.runAddTemplate) | |
} | |
let update = | |
command "templates:update" { | |
description "Updates an existing template in the templates database" | |
inputs (repoName, branch, yes) | |
setHandler (buildArgs >> Handlers.runUpdateTemplate) | |
} | |
add, update | |
let listTemplatesCmd = | |
let display = | |
Input.ArgumentWithStrings("format", "table", [ "table"; "simple" ]) | |
command "templates:list" { | |
inputs display | |
setHandler Handlers.runListTemplates | |
} | |
let removeTemplateCmd = | |
let repoName = | |
Input.Argument( | |
"templateRepositoryName", | |
"The User/repository name combination" | |
) | |
command "templates:delete" { | |
description "Removes a template from the templates database" | |
inputs (repoName) | |
setHandler Handlers.runRemoveTemplate | |
} | |
let newProjectCmd = | |
let name = Input.Argument("name", "Name of the new project") | |
let templateName = | |
Input.Argument( | |
"templateName", | |
"repository/directory combination of the template name, or the full name in case of name conflicts username/repository/directory" | |
) | |
let buildArgs (name: string, template: string) : ProjectOptions = | |
{ projectName = name | |
templateName = template } | |
command "new" { | |
description | |
"Creates a new project based on the selected template if it exists" | |
inputs (name, templateName) | |
setHandler (buildArgs >> Handlers.runNew) | |
} | |
let versionCmd = | |
let isSemver = | |
Input.OptionMaybe([ "--semver" ], "Gets the version of the application") | |
command "--version" { | |
description "Shows the full or semver version of the application" | |
inputs isSemver | |
setHandler ( | |
(fun isSemver -> isSemver |> Option.defaultValue true) | |
>> Handlers.runVersion | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Learn more about F# at http://docs.microsoft.com/dotnet/fsharp | |
open System.Threading.Tasks | |
open System.CommandLine | |
open FSharp.SystemCommandLine | |
open Perla.Commands | |
[<EntryPoint>] | |
let main argv = | |
let isInteractive = | |
Input.OptionMaybe( | |
[ "-i"; "--interactive" ], | |
"Starts the server in interactive mode" | |
) | |
let rootHandler (isInteractive: bool option) = task { return 0 } | |
rootCommand argv { | |
description "The Perla Dev Server!" | |
inputs isInteractive | |
setHandler rootHandler | |
addCommands | |
[ serveCmd | |
buildCmd | |
initCmd | |
searchPackagesCmd | |
showPackageCmd | |
removePackageCmd | |
addPacakgeCmd | |
listCmd | |
restoreCmd | |
addTemplateCmd | |
updateTemplateCmd | |
listTemplatesCmd | |
removeTemplateCmd | |
newProjectCmd | |
versionCmd ] | |
} | |
|> Async.AwaitTask | |
|> Async.RunSynchronously |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment