Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Build workspace packages in top-sorted order #1018

Merged
merged 66 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
9aff8e4
Build workspace packages in top-sorted order
JordanMartinez Sep 26, 2023
2a639d6
Drop unused With type
JordanMartinez Sep 26, 2023
4b9b936
Add tests for three cases
JordanMartinez Sep 26, 2023
cb7cb4c
Build leaves before roots
JordanMartinez Sep 26, 2023
b289a6c
Verify build order in test
JordanMartinez Sep 26, 2023
641e871
Fix dependency globs
JordanMartinez Sep 26, 2023
1eff3e5
Drop itOnly
JordanMartinez Sep 26, 2023
ca6a205
Allow Repl to work on all packages
JordanMartinez Sep 26, 2023
c5381dd
Only print info when building multiple packages
JordanMartinez Sep 26, 2023
46caa04
Duplicate code to simplify things temporarily
JordanMartinez Sep 27, 2023
9831a27
Inline getPackageConfigPath
JordanMartinez Sep 27, 2023
7fe0abd
Refactor error message; drop unneeded code
JordanMartinez Sep 27, 2023
3e36d05
Break cyclical module dependency: Repl.supportPackage
JordanMartinez Sep 27, 2023
f1b016b
Drop unused imports
JordanMartinez Sep 27, 2023
8f91238
Refactor Fetch.run to support Build.run's multi-package build
JordanMartinez Sep 27, 2023
990ef22
Drop old comments
JordanMartinez Sep 27, 2023
f92fda0
Revert `hasTests` removal
JordanMartinez Sep 27, 2023
5bd3e39
Merge remote-tracking branch 'origin/master' into build-via-topo-sort
JordanMartinez Sep 27, 2023
ab977f4
Merge branch 'master' into build-via-topo-sort
f-f Sep 28, 2023
1d65933
Update comment about ImportedPackages
JordanMartinez Sep 28, 2023
c4cc4a2
Refactor Graph to expose more internals
JordanMartinez Sep 28, 2023
97efc0e
Add duplicate module check when building workspace
JordanMartinez Sep 28, 2023
ccf3f91
Add xOrDieWith utils
JordanMartinez Sep 28, 2023
4d920de
Fix test module name
JordanMartinez Sep 28, 2023
e895f34
Include file path to duplicate module in error
JordanMartinez Sep 28, 2023
2dde00b
Drop itOnly
JordanMartinez Sep 28, 2023
c4c092d
Use OS-independent paths
JordanMartinez Sep 28, 2023
3f4e55b
Merge branch 'master' into build-via-topo-sort
JordanMartinez Sep 28, 2023
d0f5f85
Use record args; rename check functions
JordanMartinez Sep 28, 2023
f09f956
Cleanup ImportedPackages comment
JordanMartinez Sep 28, 2023
2d7e941
Drop runGraphCheck run code in build
JordanMartinez Sep 28, 2023
885e692
Make impossible state impossible
JordanMartinez Sep 28, 2023
37d4724
Make it easier to construct a config value
JordanMartinez Sep 28, 2023
8c34b10
Replace fixtures with inline code; move to own module
JordanMartinez Sep 28, 2023
7b6127a
Undo explicit re-exports change
JordanMartinez Sep 28, 2023
8d1ea05
Merge branch 'master' into build-via-topo-sort
f-f Sep 29, 2023
06b28e7
Drop dependencies
JordanMartinez Sep 29, 2023
6f7ce28
Get rid of misc compiler warnings
JordanMartinez Sep 29, 2023
344e2cf
Drop itOnly/describeOnly & run all tests
JordanMartinez Sep 29, 2023
48755d5
Merge remote-tracking branch 'origin/master' into build-via-topo-sort
JordanMartinez Sep 29, 2023
94c8ac7
Refactor to Fetch.getAllDependencies
JordanMartinez Oct 1, 2023
ec0e3be
Refactor supportPackage into Spago.Repl
JordanMartinez Oct 1, 2023
5ce8177
Fix typo: getToplogicallySortedWorkspacePackages
JordanMartinez Oct 1, 2023
1756c99
Use updated selected value
JordanMartinez Oct 1, 2023
d1c5b4b
Replace These with an isomorphic-but-renamed type
JordanMartinez Oct 1, 2023
a7e3038
Replace Either with PackageSelection type
JordanMartinez Oct 1, 2023
beadb4c
Unify getBuildGlobs/EntireWorkspaceGlobs
JordanMartinez Oct 2, 2023
323d183
Merge remote-tracking branch 'origin/master' into build-via-topo-sort
JordanMartinez Oct 2, 2023
47a4df5
Move depsOnly comment near first usage
JordanMartinez Oct 3, 2023
7fdf527
Write workspace `spago.yaml` in tests; explain why
JordanMartinez Oct 3, 2023
f1c92ef
Copy mermaid diagrams into module comment
JordanMartinez Oct 3, 2023
7568ac7
Add installingPackages for clarity of null check
JordanMartinez Oct 3, 2023
dad5b49
Use callback to finish single package; account for ensureRanges
JordanMartinez Oct 3, 2023
0f7f404
Define util function: ensure same representation
JordanMartinez Oct 3, 2023
f6c5152
Refactor duplicate modules error into function
JordanMartinez Oct 3, 2023
165bda7
Refactor code to prevent shadowed name on dependencies
JordanMartinez Oct 3, 2023
8ed928e
Revert back to original approach
JordanMartinez Oct 4, 2023
78474bd
Define type alias, rename function, rename to dependencies
JordanMartinez Oct 4, 2023
8b416e1
Call Config.getWorkspacePackages within getBuildGlobs
JordanMartinez Oct 4, 2023
c803de0
Merge remote-tracking branch 'origin/master' into build-via-topo-sort
JordanMartinez Oct 4, 2023
1db9ae2
Further reduce diff
JordanMartinez Oct 4, 2023
531ccaf
Move each mermaid diagram above test case
JordanMartinez Oct 4, 2023
90b7656
Nest cases 1-3 under topological build order
JordanMartinez Oct 4, 2023
34ea88c
Rename util function
JordanMartinez Oct 4, 2023
e053f18
Add ensure-ranges test in mono-/poly-repo setup
JordanMartinez Oct 4, 2023
927db28
Merge branch 'master' into build-via-topo-sort
JordanMartinez Oct 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 26 additions & 25 deletions bin/src/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ main =
Install args@{ packages, selectedPackage, ensureRanges, testDeps } -> do
{ env, fetchOpts } <- mkFetchEnv { packages, selectedPackage, ensureRanges, testDeps }
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
let
buildArgs = Record.merge
args
Expand All @@ -488,20 +488,20 @@ main =
, strict: Nothing :: Maybe Boolean
, persistWarnings: Nothing :: Maybe Boolean
}
env' <- runSpago env (mkBuildEnv buildArgs dependencies)
env' <- runSpago env (mkBuildEnv buildArgs dependencyInfo)
let options = { depsOnly: true, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false }
runSpago env' (Build.run options)
Build args@{ selectedPackage, ensureRanges, jsonErrors } -> do
{ env, fetchOpts } <- mkFetchEnv { packages: mempty, selectedPackage, ensureRanges, testDeps: false }
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
buildEnv <- runSpago env (mkBuildEnv args dependencies)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
buildEnv <- runSpago env (mkBuildEnv args dependencyInfo)
let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors }
runSpago buildEnv (Build.run options)
Publish { selectedPackage } -> do
{ env, fetchOpts } <- mkFetchEnv { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false }
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
let
buildArgs =
{ selectedPackage
Expand All @@ -519,8 +519,8 @@ main =
, strict: Nothing :: Maybe Boolean
, persistWarnings: Nothing :: Maybe Boolean
}
{ purs } <- runSpago env (mkBuildEnv buildArgs dependencies)
publishEnv <- runSpago env (mkPublishEnv dependencies purs)
{ purs } <- runSpago env (mkBuildEnv buildArgs dependencyInfo)
publishEnv <- runSpago env (mkPublishEnv dependencyInfo purs)
void $ runSpago publishEnv (Publish.publish {})

Repl args@{ selectedPackage } -> do
Expand Down Expand Up @@ -548,37 +548,37 @@ main =
, ensureRanges: false
, testDeps: false
}
dependencies <- runSpago env (Fetch.run fetchOpts)
supportPackages <- runSpago env (Repl.supportPackage env.workspace.packageSet)
replEnv <- runSpago env (mkReplEnv args (Map.union dependencies supportPackages))
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
supportPackages <- runSpago env (Fetch.replSupportPackage env.workspace.packageSet)
replEnv <- runSpago env (mkReplEnv args (Map.union dependencyInfo.dependencies supportPackages))
void $ runSpago replEnv Repl.run

Bundle args@{ selectedPackage, ensureRanges } -> do
{ env, fetchOpts } <- mkFetchEnv { packages: mempty, selectedPackage, ensureRanges, testDeps: false }
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
-- TODO: --no-build flag
buildEnv <- runSpago env (mkBuildEnv args dependencies)
buildEnv <- runSpago env (mkBuildEnv args dependencyInfo)
let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false }
runSpago buildEnv (Build.run options)
bundleEnv <- runSpago env (mkBundleEnv args)
runSpago bundleEnv Bundle.run
Run args@{ selectedPackage, ensureRanges } -> do
{ env, fetchOpts } <- mkFetchEnv { packages: mempty, selectedPackage, ensureRanges, testDeps: false }
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
-- TODO: --no-build flag
buildEnv <- runSpago env (mkBuildEnv args dependencies)
buildEnv <- runSpago env (mkBuildEnv args dependencyInfo)
let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false }
runSpago buildEnv (Build.run options)
runEnv <- runSpago env (mkRunEnv args buildEnv)
runSpago runEnv Run.run
Test args@{ selectedPackage } -> do
{ env, fetchOpts } <- mkFetchEnv { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false }
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
-- TODO: --no-build flag
buildEnv <- runSpago env (mkBuildEnv (Record.union args { ensureRanges: false }) dependencies)
buildEnv <- runSpago env (mkBuildEnv (Record.union args { ensureRanges: false }) dependencyInfo)
let options = { depsOnly: false, pursArgs: List.toUnfoldable args.pursArgs, jsonErrors: false }
runSpago buildEnv (Build.run options)
testEnv <- runSpago env (mkTestEnv args buildEnv)
Expand All @@ -587,15 +587,15 @@ main =
let fetchArgs = { packages: mempty, selectedPackage: Nothing, ensureRanges: false, testDeps: false }
{ env: env@{ workspace }, fetchOpts } <- mkFetchEnv fetchArgs
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
let lsEnv = { workspace, dependencies, logOptions }
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
let lsEnv = { workspace, dependencies: dependencyInfo.dependencies, logOptions }
runSpago lsEnv (Ls.listPackageSet args)
LsDeps { selectedPackage, json, transitive } -> do
let fetchArgs = { packages: mempty, selectedPackage, ensureRanges: false, testDeps: false }
{ env, fetchOpts } <- mkFetchEnv fetchArgs
-- TODO: --no-fetch flag
dependencies <- runSpago env (Fetch.run fetchOpts)
lsEnv <- runSpago env (mkLsEnv dependencies)
dependencyInfo <- runSpago env (Fetch.run fetchOpts)
lsEnv <- runSpago env (mkLsEnv dependencyInfo.dependencies)
runSpago lsEnv (Ls.listPackages { json, transitive })

mkLogOptions :: GlobalArgs -> Aff LogOptions
Expand Down Expand Up @@ -757,9 +757,9 @@ mkBuildEnv
, persistWarnings :: Maybe Boolean
| r
}
-> Map PackageName Package
-> Fetch.PackageDependencyInfo
-> Spago (Fetch.FetchEnv ()) (Build.BuildEnv ())
mkBuildEnv buildArgs dependencies = do
mkBuildEnv buildArgs { packageDependencies, dependencies } = do
{ logOptions, workspace, git } <- ask
purs <- Purs.getPurs
let
Expand Down Expand Up @@ -788,12 +788,13 @@ mkBuildEnv buildArgs dependencies = do
{ logOptions
, purs
, git
, packageDependencies
, dependencies
, workspace: newWorkspace
}

mkPublishEnv :: forall a. Map PackageName Package -> Purs -> Spago (Fetch.FetchEnv a) (Publish.PublishEnv a)
mkPublishEnv dependencies purs = do
mkPublishEnv :: forall a. Fetch.PackageDependencyInfo -> Purs -> Spago (Fetch.FetchEnv a) (Publish.PublishEnv a)
mkPublishEnv dependencyInfo purs = do
env <- ask
selected <- case env.workspace.selected of
Just s -> pure s
Expand All @@ -810,7 +811,7 @@ mkPublishEnv dependencies purs = do
[ toDoc "No package was selected for publishing. Please select (with -p) one of the following packages:"
, indent (toDoc $ map _.package.name workspacePackages)
]
pure (Record.union { purs, selected, dependencies } env)
pure (Record.union { purs, selected } $ Record.union dependencyInfo env)

mkReplEnv :: forall a. ReplArgs -> Map PackageName Package -> Spago (Fetch.FetchEnv a) (Repl.ReplEnv ())
mkReplEnv replArgs dependencies = do
Expand Down
121 changes: 62 additions & 59 deletions src/Spago/Command/Build.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import Spago.Prelude

import Control.Alternative as Alternative
import Data.Array as Array
import Data.Either (note)
import Data.Map as Map
import Data.Set as Set
import Data.Set.NonEmpty as NonEmptySet
import Data.Tuple as Tuple
import Registry.PackageName as PackageName
import Spago.BuildInfo as BuildInfo
import Spago.Cmd as Cmd
import Spago.Config (Package(..), WithTestGlobs(..), Workspace, WorkspacePackage)
import Spago.Config (Package(..), WithTestGlobs(..), Workspace, WorkspacePackage, PackageMap)
import Spago.Config as Config
import Spago.Git (Git)
import Spago.Paths as Paths
Expand All @@ -27,7 +28,8 @@ import Spago.Purs.Graph as Graph
type BuildEnv a =
{ purs :: Purs
, git :: Git
, dependencies :: Map PackageName Package
, packageDependencies :: Map PackageName PackageMap
, dependencies :: PackageMap
, logOptions :: LogOptions
, workspace :: Workspace
| a
Expand All @@ -42,13 +44,10 @@ type BuildOptions =
run :: forall a. BuildOptions -> Spago (BuildEnv a) Unit
run opts = do
logInfo "Building..."
{ dependencies
{ packageDependencies
, workspace
, logOptions
} <- ask
let
{ yes: _monorepoPkgs, no: dependencyPkgs } = partition isWorkspacePackage $ Map.toUnfoldable dependencies
dependencyLibs = map (Tuple.uncurry Config.getPackageLocation) dependencyPkgs

BuildInfo.writeBuildInfo

Expand All @@ -70,44 +69,6 @@ run opts = do
, "Use the --json-errors flag for Spago."
]

let
psaArgs =
{ libraryDirs: dependencyLibs
, color: logOptions.color
, jsonErrors: opts.jsonErrors
}
psaOptions =
{ strict: fromMaybe Psa.defaultParseOptions.strict workspace.buildOptions.strict
, censorBuildWarnings: fromMaybe Psa.defaultParseOptions.censorBuildWarnings workspace.buildOptions.censorBuildWarnings
, showSource: fromMaybe Psa.defaultParseOptions.showSource workspace.buildOptions.showSource
, censorCodes: maybe Psa.defaultParseOptions.censorCodes NonEmptySet.toSet workspace.buildOptions.censorCodes
, filterCodes: maybe Psa.defaultParseOptions.filterCodes NonEmptySet.toSet workspace.buildOptions.filterCodes
, statVerbosity: fromMaybe Psa.defaultParseOptions.statVerbosity workspace.buildOptions.statVerbosity
, stashFile: do
Alternative.guard (not opts.depsOnly)
shouldStashWarnings <- workspace.buildOptions.persistWarnings
Alternative.guard shouldStashWarnings
case workspace.selected of
Just p -> Just $ Paths.mkLocalCachesPersistentWarningsFile $ PackageName.print p.package.name
Nothing -> Just Paths.localCachesPersistedWarningsEntireWorkspace
}
buildBackend = do
case workspace.backend of
Nothing -> pure unit
Just backend -> do
logInfo $ "Compiling with backend \"" <> backend.cmd <> "\""
logDebug $ "Running command `" <> backend.cmd <> "`"
let
moreBackendArgs = case backend.args of
Just as | Array.length as > 0 -> as
_ -> []
Cmd.exec backend.cmd (addOutputArgs moreBackendArgs) Cmd.defaultExecOptions >>= case _ of
Left err -> do
logDebug $ show err
die [ "Failed to build with backend " <> backend.cmd ]
Right _r ->
logSuccess "Backend build succeeded."

{-
TODO: before, then, else
buildAction globs = do
Expand All @@ -132,31 +93,78 @@ run opts = do
Just _ -> ""
]

let
selectedPackages = case workspace.selected of
Just p -> [ p ]
Nothing -> Config.getToplogicallySortedWorkspacePackages workspace.packageSet
selectedPackages :: Array (Tuple WorkspacePackage PackageMap) <- case workspace.selected of
Just p -> case Map.lookup p.package.name packageDependencies of
Just allDeps -> pure [ Tuple p allDeps ]
Nothing -> die [ "Internal error. Did not get transitive dependencies for selected package: " <> PackageName.print p.package.name ]
Nothing -> do
let
getTransDeps :: WorkspacePackage -> Either WorkspacePackage PackageMap
getTransDeps p = note p $ Map.lookup p.package.name packageDependencies

result :: Either WorkspacePackage (Array (Tuple WorkspacePackage PackageMap))
result = traverse (\p -> Tuple p <$> getTransDeps p) $ Config.getToplogicallySortedWorkspacePackages workspace.packageSet
case result of
Right a -> pure a
Left p -> die [ "Internal error. Did not get transitive dependencies for package: " <> PackageName.print p.package.name ]

let buildingMultiplePackages = Array.length selectedPackages > 1

when buildingMultiplePackages do
logInfo
$ append "Building packages in the following order:\n"
$ Array.intercalate "\n"
$ Array.mapWithIndex (\i p -> show (i + 1) <> ") " <> PackageName.print p.package.name) selectedPackages
for_ selectedPackages \selected -> do
$ Array.mapWithIndex (\i (Tuple p _) -> show (i + 1) <> ") " <> PackageName.print p.package.name) selectedPackages
for_ selectedPackages \(Tuple selected allDependencies) -> do
when buildingMultiplePackages do
logInfo $ "Building package: " <> PackageName.print selected.package.name
let
globs = getBuildGlobs
{ dependencies
{ dependencies: allDependencies
, depsOnly: opts.depsOnly
, withTests: true
, selected
}
{ no: dependencyPkgs :: Array _ } = partition isWorkspacePackage $ Map.toUnfoldable allDependencies
dependencyLibs = map (Tuple.uncurry Config.getPackageLocation) dependencyPkgs
psaArgs =
{ libraryDirs: dependencyLibs
, color: logOptions.color
, jsonErrors: opts.jsonErrors
}
psaOptions =
{ strict: fromMaybe Psa.defaultParseOptions.strict workspace.buildOptions.strict
, censorBuildWarnings: fromMaybe Psa.defaultParseOptions.censorBuildWarnings workspace.buildOptions.censorBuildWarnings
, showSource: fromMaybe Psa.defaultParseOptions.showSource workspace.buildOptions.showSource
, censorCodes: maybe Psa.defaultParseOptions.censorCodes NonEmptySet.toSet workspace.buildOptions.censorCodes
, filterCodes: maybe Psa.defaultParseOptions.filterCodes NonEmptySet.toSet workspace.buildOptions.filterCodes
, statVerbosity: fromMaybe Psa.defaultParseOptions.statVerbosity workspace.buildOptions.statVerbosity
, stashFile: do
Alternative.guard (not opts.depsOnly)
shouldStashWarnings <- workspace.buildOptions.persistWarnings
Alternative.guard shouldStashWarnings
case workspace.selected of
Just p -> Just $ Paths.mkLocalCachesPersistentWarningsFile $ PackageName.print p.package.name
Nothing -> Just Paths.localCachesPersistedWarningsEntireWorkspace
}

Psa.psaCompile globs args psaArgs psaOptions

buildBackend
case workspace.backend of
Nothing -> pure unit
Just backend -> do
logInfo $ "Compiling with backend \"" <> backend.cmd <> "\""
logDebug $ "Running command `" <> backend.cmd <> "`"
let
moreBackendArgs = case backend.args of
Just as | Array.length as > 0 -> as
_ -> []
Cmd.exec backend.cmd (addOutputArgs moreBackendArgs) Cmd.defaultExecOptions >>= case _ of
Left err -> do
logDebug $ show err
die [ "Failed to build with backend " <> backend.cmd ]
Right _r ->
logSuccess "Backend build succeeded."

when workspace.buildOptions.pedanticPackages do
logInfo $ "Looking for unused and undeclared transitive dependencies..."
Expand All @@ -171,7 +179,7 @@ type BuildGlobsOptions =
{ withTests :: Boolean
, depsOnly :: Boolean
, selected :: WorkspacePackage
, dependencies :: Map PackageName Package
, dependencies :: PackageMap
}

getBuildGlobs :: BuildGlobsOptions -> Set FilePath
Expand All @@ -192,12 +200,7 @@ getBuildGlobs { selected, dependencies, withTests, depsOnly } =
workspacePackageGlob :: WorkspacePackage -> Array String
workspacePackageGlob p = Config.sourceGlob testGlobs p.package.name (WorkspacePackage p)

{ yes: monorepoPkgs, no: dependencyPkgs } = partition isWorkspacePackage
$ Array.mapMaybe (\pkgName -> Tuple pkgName <$> Map.lookup pkgName dependencies)
$ Array.fromFoldable
$ Map.keys
$ unwrap
$ selected.package.dependencies
{ yes: monorepoPkgs, no: dependencyPkgs } = partition isWorkspacePackage $ Map.toUnfoldable dependencies

-- depsOnly means "no packages from the monorepo", so we filter out the workspace packages
dependencyGlobs = (Tuple.uncurry $ Config.sourceGlob NoTestGlobs) =<< dependencyPkgs
Expand Down
1 change: 0 additions & 1 deletion src/Spago/Command/Bundle.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module Spago.Command.Bundle where
import Spago.Prelude

import Node.Path as Path
import Data.String (Pattern(..), Replacement(..))
import Data.String as String
import Spago.Cmd as Cmd
import Spago.Esbuild (Esbuild)
Expand Down
Loading