Build js packages at code-generation time (#5171)

changelog_begin
changelog_end
This commit is contained in:
Shayne Fletcher 2020-03-25 14:13:37 -04:00 committed by GitHub
parent 1a229ebb7b
commit 9351b7a7b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 192 additions and 187 deletions

View File

@ -71,14 +71,19 @@ da_haskell_test(
name = "integration-tests",
timeout = "long",
srcs = glob(["src/**/*.hs"]),
args = [
"$(location //:yarn)",
"daml-types-not-available" if is_windows else "$(location //language-support/ts/daml-types:npm_package)",
],
data = [
":integration-tests-mvn",
"//release:sdk-release-tarball",
"@local_jdk//:bin/java.exe" if is_windows else "@local_jdk//:bin/java",
"//:yarn",
"//compiler/damlc/tests:generate-simple-dalf",
"@mvn_dev_env//:mvn",
"@tar_dev_env//:tar",
],
] + ([] if is_windows else ["//language-support/ts/daml-types:npm_package"]),
# Im sure the mvn stuff will be flaky.
flaky = True,
hackage_deps = [

View File

@ -31,33 +31,43 @@ import Test.Main
import Test.Tasty
import Test.Tasty.HUnit
import qualified Web.JWT as JWT
import qualified Data.ByteString.Lazy as BSL
import qualified Data.HashMap.Strict as HMS
import Data.Aeson
import DA.Directory
import DA.Bazel.Runfiles
import DA.Daml.Helper.Run
import SdkVersion
main :: IO ()
main =
withTempDir $ \tmpDir -> do
main = do
setEnv "TASTY_NUM_THREADS" "1" True
-- We manipulate global state via the working directory and
-- the environment so running tests in parallel will cause trouble.
setEnv "TASTY_NUM_THREADS" "1" True
yarn : damlTypesPath : args <- getArgs
withTempDir $ \tmpDir -> do
oldPath <- getSearchPath
javaPath <- locateRunfiles "local_jdk/bin"
mvnPath <- locateRunfiles "mvn_dev_env/bin"
tarPath <- locateRunfiles "tar_dev_env/bin"
yarnPath <- takeDirectory <$> locateRunfiles (mainWorkspace </> yarn)
damlTypesDir <-
if isWindows
then pure damlTypesPath -- Not available.
else locateRunfiles (mainWorkspace </> damlTypesPath)
-- NOTE: `COMSPEC` env. variable on Windows points to cmd.exe, which is required to be present
-- on the PATH as mvn.cmd executes cmd.exe
mbComSpec <- getEnv "COMSPEC"
let mbCmdDir = takeDirectory <$> mbComSpec
let damlDir = tmpDir </> "daml"
withEnv
withArgs args (withEnv
[ ("DAML_HOME", Just damlDir)
, ("PATH", Just $ intercalate [searchPathSeparator] $ ((damlDir </> "bin") : tarPath : javaPath : mvnPath : oldPath) ++ maybeToList mbCmdDir)
] $ defaultMain (tests damlDir tmpDir)
, ("PATH", Just $ intercalate [searchPathSeparator] $ ((damlDir </> "bin") : tarPath : javaPath : mvnPath : yarnPath : oldPath) ++ maybeToList mbCmdDir)
] $ defaultMain (tests damlDir tmpDir damlTypesDir))
tests :: FilePath -> FilePath -> TestTree
tests damlDir tmpDir = testGroup "Integration tests"
tests :: FilePath -> FilePath -> FilePath -> TestTree
tests damlDir tmpDir damlTypesDir = testGroup "Integration tests"
[ testCase "install" $ do
releaseTarball <- locateRunfiles (mainWorkspace </> "release" </> "sdk-release-tarball.tar.gz")
createDirectory tarballDir
@ -78,7 +88,7 @@ tests damlDir tmpDir = testGroup "Integration tests"
, quickstartTests quickstartDir mvnDir
, cleanTests cleanDir
, deployTest deployDir
, codegenTests codegenDir
, codegenTests codegenDir damlTypesDir
]
where quickstartDir = tmpDir </> "q-u-i-c-k-s-t-a-r-t"
cleanDir = tmpDir </> "clean"
@ -474,12 +484,15 @@ cleanTests baseDir = testGroup "daml clean"
]
-- | Check we can generate language bindings.
codegenTests :: FilePath -> TestTree
codegenTests codegenDir = testGroup "daml codegen"
[ codegenTestFor "ts" Nothing
, codegenTestFor "java" Nothing
codegenTests :: FilePath -> FilePath -> TestTree
codegenTests codegenDir damlTypes = testGroup "daml codegen" (
[ codegenTestFor "java" Nothing
, codegenTestFor "scala" (Just "com.cookiemonster.nomnomnom")
]
] ++
-- The 'daml-types' NPM package is not available on Windows which
-- is required by 'daml2ts'.
[ codegenTestFor "ts" Nothing | not isWindows ]
)
where
codegenTestFor :: String -> Maybe String -> TestTree
codegenTestFor lang namespace =
@ -490,8 +503,22 @@ codegenTests codegenDir = testGroup "daml codegen"
callCommandQuiet $ unwords ["daml new", projectDir, "skeleton"]
withCurrentDirectory projectDir $ do
callCommandQuiet "daml build"
let darFile = projectDir</> ".daml/dist/proj-" ++ lang ++ "-0.0.1.dar"
outDir = projectDir</> "generated" </> lang
let darFile = projectDir </> ".daml/dist/proj-" ++ lang ++ "-0.0.1.dar"
outDir = projectDir </> "generated" </> lang
when (lang == "ts") $ do
createDirectoryIfMissing True "generated"
withCurrentDirectory "generated" $ do
-- SDK version is 0.0.0; daml2ts needs
-- 'daml-types' to be here in the filesystem...
copyDirectory damlTypes "daml-types"
BSL.writeFile "package.json" $ encode (
-- ... and this package.json so it can find it.
object
[ "private" .= True
, "workspaces" .= [T.pack lang]
, "resolutions" .= HMS.fromList ([("@daml/types", "file:daml-types")] :: [(T.Text, T.Text)])
]
)
callCommandQuiet $
unwords [ "daml", "codegen", lang
, darFile ++ maybe "" ("=" ++) namespace

View File

@ -21,7 +21,7 @@ Usage
``daml2ts`` is invoked via the DAML SDK assistant.
In outline, the command to generate TypeScript from DAML is ``daml codegen ts DAR -o OUTDIR main-package-name=PACKAGE`` where ``DAR`` is the path to a DAR file (generated via ``daml build``), ``OUTDIR`` is a directory where you want the TypeScript to be written and ``PACKAGE`` is a desired TypeScript package name.
In outline, the command to generate TypeScript from DAML is ``daml codegen ts DAR -o OUTDIR`` where ``DAR`` is the path to a DAR file (generated via ``daml build``), ``OUTDIR`` is a directory where you want the TypeScript to be written and ``PACKAGE`` is a desired TypeScript package name.
Here's a complete example that generates TypeScript from a project produced from the standard "skeleton" template.
@ -31,15 +31,15 @@ Here's a complete example that generates TypeScript from a project produced from
daml new my-proj skeleton # Create a new project based off the skeleton template
cd my-proj # Enter the newly created project directory
daml build # Compile the project's DAML files into a DAR
daml codegen ts .daml/dist/my-proj-0.0.1.dar -o generated/ts --main-package-name=my-proj # Generate Typescript from the DAR
daml codegen ts .daml/dist/my-proj-0.0.1.dar -o daml2ts # Generate script bindings from the DAR
- On execution of these commands:
- The directory ``my-proj/generated/ts`` contains the generated TypeScript source files;
- The directory ``my-proj/daml2ts`` contains generated TypeScript and Javascript artifacts;
- The files are arranged into directories;
- One of those directories will be named as per the ``PACKAGE`` argument and will contain the TypeScript definitions corresponding to the DAML files in the project;
- For example, ``generated/ts/my-proj/Main.ts`` contains the TypeScript definitions for ``daml/Main.daml``;
- The remaining directories contain supporting TypeScript corresponding to modules of the DAML standard library;
- One of those directories will be named as per the ``PACKAGE`` argument and will contain the definitions corresponding to the DAML files in the project;
- For example, ``generated/ts/my-proj/Main.ts`` contains the definitions for ``daml/Main.daml``;
- The remaining directories correspond to modules of the DAML standard library;
- Those directories have numeric names (the names are hashes of the DAML-LF package they are derived from).
To get a quickstart idea of how to use what has been generated, you may wish to jump to the `Templates and choices`_ section and return to the reference material that follows as needed.

View File

@ -19,6 +19,7 @@ da_haskell_binary(
"hashable",
"lens",
"optparse-applicative",
"process",
"text",
"unordered-containers",
"zip-archive",

View File

@ -3,6 +3,7 @@
{-# LANGUAGE DerivingStrategies #-}
module TsCodeGenMain (main) where
import DA.Directory
import qualified DA.Daml.LF.Proto3.Archive as Archive
import qualified DA.Daml.LF.Reader as DAR
import qualified DA.Pretty
@ -20,7 +21,6 @@ import Data.Aeson hiding (Options)
import Data.Aeson.Encode.Pretty
import Data.Hashable
import Control.Exception
import Control.Monad.Extra
import DA.Daml.LF.Ast
import DA.Daml.LF.Ast.Optics
@ -30,11 +30,12 @@ import Data.Graph
import Data.Maybe
import Data.Bifoldable
import Options.Applicative
import System.IO.Error
import System.Directory
import System.FilePath hiding ((<.>), (</>))
import System.FilePath.Posix((</>)) -- Make sure we generate / on all platforms.
import qualified System.FilePath as FP
import System.Process
import System.Exit
import DA.Daml.Project.Consts
import DA.Daml.Project.Types
@ -54,10 +55,7 @@ configConsts sdkVersion = ConfigConsts
, (NpmPackageName "@daml/types", NpmPackageVersion sdkVersion)
]
, pkgDevDependencies = HMS.fromList
[ (NpmPackageName "@typescript-eslint/eslint-plugin", NpmPackageVersion "2.11.0")
, (NpmPackageName "@typescript-eslint/parser", NpmPackageVersion "2.11.0")
, (NpmPackageName "eslint", NpmPackageVersion "^6.7.2")
, (NpmPackageName "typescript", NpmPackageVersion "~3.7.3")
[ (NpmPackageName "typescript", NpmPackageVersion "~3.7.3")
]
, pkgScripts = HMS.fromList
[ (ScriptName "build", Script "tsc")
@ -80,7 +78,7 @@ newtype Script = Script {unScript :: T.Text}
data Options = Options
{ optInputDars :: [FilePath]
, optOutputDir :: FilePath
, optInputPackageJson :: FilePath
, optInputPackageJson :: Maybe FilePath -- Deprecated.
, optScope :: Scope -- Defaults to 'daml.js'.
}
@ -95,12 +93,11 @@ optionsParser = Options
<> metavar "DIR"
<> help "Output directory for the generated packages"
)
<*> strOption
<*> optional (strOption
( short 'p'
<> metavar "PACKAGE-JSON"
<> value "package.json"
<> help "Path to a 'package.json' to update (or create if missing)"
)
<> help "This flag is deprecated and ignored"
))
<*> (Scope . ("@" <>) <$> strOption
( short 's'
<> metavar "SCOPE"
@ -159,6 +156,8 @@ mergePackageMap ps = foldM merge Map.empty ps
main :: IO ()
main = do
opts@Options{..} <- execParser optionsParserInfo
when (isJust optInputPackageJson) $
putStrLn "WARNING: Use of the flag '-p' is deprecated. This flag is ignored."
sdkVersionOrErr <- DATypes.parseVersion . T.pack . fromMaybe "0.0.0" <$> getSdkVersionMaybe
sdkVersion <- case sdkVersionOrErr of
Left _ -> fail "Invalid SDK version"
@ -177,13 +176,13 @@ main = do
Just pkgName -> unPackageName pkgName <> " (hash: " <> id <> ")"
T.putStrLn $ "Generating " <> pkgDesc
daml2ts Daml2TsParams{..}
setupWorkspace optInputPackageJson optOutputDir dependencies
buildPackages sdkVersion optScope optOutputDir dependencies
packageNameText :: PackageId -> Maybe PackageName -> T.Text
packageNameText pkgId mbPkgIdent = maybe (unPackageId pkgId) unPackageName mbPkgIdent
newtype Scope = Scope T.Text
newtype Dependency = Dependency {unDependency :: T.Text} deriving (Eq, Ord)
newtype Scope = Scope {unScope :: T.Text}
newtype Dependency = Dependency {unDependency :: T.Text} deriving (Eq, Ord)
data Daml2TsParams = Daml2TsParams
{ opts :: Options -- cli args
@ -698,67 +697,47 @@ writePackageJson packageDir sdkVersion (Scope scope) depends =
, "main" .= ("lib/index.js" :: T.Text)
, "types" .= ("lib/index.d.ts" :: T.Text)
, "description" .= ("Generated by daml2ts" :: T.Text)
, "dependencies" .= (pkgDependencies config <> dependencies)
, "devDependencies" .= pkgDevDependencies config
, "dependencies" .= dependencies
, "scripts" .= pkgScripts config
]
where
config = configConsts sdkVersion
-- This type describes the format of a "top-level" 'package.json'. We
-- expect such files to have the format
-- {
-- "workspaces: [
-- "path/to/foo",
-- "path/to/bar",
-- ...
-- ],
-- ... perhaps other stuff ...
-- }
data PackageJson = PackageJson
{ workspaces :: [T.Text]
, otherFields :: Object
}
deriving Show
instance Semigroup PackageJson where
l <> r = PackageJson (workspaces l <> workspaces r) (otherFields l <> otherFields r)
instance Monoid PackageJson where
mempty = PackageJson mempty mempty
instance FromJSON PackageJson where
parseJSON (Object v) = PackageJson
<$> v .: "workspaces"
<*> pure (HMS.delete "workspaces" v)
parseJSON _ = mzero
instance ToJSON PackageJson where
toJSON PackageJson{..} = Object (HMS.insert "workspaces" (toJSON workspaces) otherFields)
-- Read the provided 'package.json'; transform it to include the
-- provided workspaces; write it back to disk.
setupWorkspace :: FilePath -> FilePath -> [(T.Text, [Dependency])] -> IO ()
setupWorkspace optInputPackageJson optOutputDir dependencies = do
buildPackages :: SdkVersion -> Scope -> FilePath -> [(T.Text, [Dependency])] -> IO ()
buildPackages sdkVersion optScope optOutputDir dependencies = do
let (g, nodeFromVertex) = graphFromEdges'
(map (\(a, ds) -> (a, a, map unDependency ds)) dependencies)
ps = map (fst3 . nodeFromVertex) $ reverse (topSort g)
-- Topologically order our packages.
outBaseDir = T.pack $ takeFileName optOutputDir
-- The leaf directory of the output directory (e.g. often 'daml2ts').
let ourWorkspaces = map ((outBaseDir <> "/") <>) ps
mbBytes <- catchJust (guard . isDoesNotExistError)
(Just <$> BSL.readFile optInputPackageJson) (const $ pure Nothing)
packageJson <- case mbBytes of
Nothing -> pure mempty
Just bytes ->
case eitherDecode @PackageJson bytes of
Left msg -> fail $ "Error : '" <> optInputPackageJson <> "' : " <> msg
Right packageJson -> pure packageJson
transformAndWrite ourWorkspaces outBaseDir packageJson
pkgs = map (T.unpack . fst3 . nodeFromVertex) $ reverse (topSort g)
withCurrentDirectory optOutputDir $ do
BSL.writeFile "package.json" $ encodePretty packageJson
callProcessSilent "yarn" ["install", "--pure-lockfile"]
createDirectoryIfMissing True $ "node_modules" </> scope
mapM_ build pkgs
removeFile "package.json" -- Any subsequent runs will regenerate it.
-- We don't remove 'node_modules' : subsequent runs can benefit from caching.
where
transformAndWrite :: [T.Text] -> T.Text -> PackageJson -> IO ()
transformAndWrite ourWorkspaces outBaseDir packageJson = do
let keepWorkspaces = filter (not . T.isPrefixOf outBaseDir) $ workspaces packageJson
-- Old versions of our packages should be removed.
allWorkspaces = ourWorkspaces ++ keepWorkspaces
-- Our packages need to come before any other existing packages.
BSL.writeFile optInputPackageJson $ encodePretty packageJson{workspaces=allWorkspaces}
putStrLn $ "'" <> optInputPackageJson <> "' created or updated."
packageJson :: Value
packageJson = object
[ "name" .= ("daml2ts" :: T.Text)
, "version" .= version
, "dependencies" .= pkgDependencies config
, "devDependencies" .= pkgDevDependencies config
]
scope = T.unpack $ unScope optScope
config = configConsts version
version = versionToText sdkVersion
build :: String -> IO ()
build pkg = do
putStrLn $ "Building " <> pkg
callProcessSilent "yarn" ["run", "tsc", "--project", pkg </> "tsconfig.json"]
copyDirectory pkg $ "node_modules" </> scope </> pkg
callProcessSilent :: FilePath -> [String] -> IO ()
callProcessSilent cmd args = do
(exitCode, _, err) <- readProcessWithExitCode cmd args ""
unless (exitCode == ExitSuccess) $ do
putStrLn $ "Failure: Command \"" <> cmd <> " " <> unwords args <> "\" exited with " <> show exitCode
putStrLn err
exitFailure

View File

@ -30,7 +30,7 @@ daml_compile(
# - 'ts/codegen/tests/daml/*'
# The DAML that goes into the DAR ('build-and-lint-1.0.0.dar');
# - 'ts/codegen/tests/ts/*'
# A skeleton yarn workspaces root containing a TypeScript package
# A yarn workspaces root containing a single TypeScript package
# 'build-and-lint-test' which houses the test driver 'test.ts'.
#
# 'build-and-lint' creates a temp directory ('root' say), and uses the
@ -43,10 +43,10 @@ daml_compile(
# __tests__/
# test.ts
# daml2ts/
# build-and-lint-1.0.0/ -- The TypeScript generated from 'build-and-lint-1.0.0.dar'
# build-and-lint-1.0.0/ -- The artifacts generated of 'build-and-lint-1.0.0.dar'
# 057eed/
# ...
# package.json -- Enumeration of the workspaces : build-and-lint, daml2ts/build-and-lint-1.0.0, ...
# package.json -- Singleton package workspace : build-and-lint-test
# node_modules/
# @daml/
# types/
@ -54,8 +54,8 @@ daml_compile(
# ...
#
# In more detail, the actions of 'build-and-lint' are to:
# - Invoke 'daml2ts' on 'build-and-lint-1.0.0.dar' produce TypeScript bindings (
# in the 'daml2ts' directory);
# - Invoke 'daml2ts' on 'build-and-lint-1.0.0.dar' to produce bindings
# (in the 'daml2ts' directory);
# - Invoke from 'root':
# - 'yarn workspaces run install';
# - 'yarn workspaces run build';
@ -136,12 +136,16 @@ da_haskell_test(
"@davl//:released/davl-v5.dar",
],
hackage_deps = [
"aeson",
"base",
"bytestring",
"extra",
"filepath",
"process",
"tasty",
"tasty-hunit",
"text",
"unordered-containers",
],
main_function = "DA.Test.Daml2Ts.main",
src_strip_prefix = "src",

View File

@ -57,11 +57,14 @@ cp -rL $DAML_LEDGER/* $TMP_DAML_LEDGER
cd $TMP_DIR
$DAML2TS -o daml2ts $DAR -p $TMP_DIR/package.json
$YARN install --frozen-lockfile
$YARN workspaces run build
$YARN workspaces run lint
# Call daml2ts.
PATH=`dirname $YARN`:$PATH $DAML2TS -o daml2ts $DAR
# The previous step provides all the daml2ts Javascript needed by the
# build-and-lint-test workspace.
$YARN install --pure-lockfile > /dev/null 2>&1
$YARN workspaces run build # Build it.
$YARN workspaces run lint # No great value in this but nonetheless, lint it.
# Invoke 'yarn test' in the 'build-and-lint-test' package
# directory. Control is thereby passed to
# 'language-support/ts/codegen/tests/ts/build-and-lint-test/src/__tests__/test.ts'.

View File

@ -15,18 +15,28 @@ import qualified DA.Daml.LF.Ast.Version as LF
import DA.Directory
import Data.Maybe
import Data.List.Extra
import qualified Data.Text.Extended as T
import qualified Data.ByteString.Lazy as BSL
import qualified Data.HashMap.Strict as HMS
import Data.Aeson
import Test.Tasty
import Test.Tasty.HUnit
main :: IO ()
main = do
setEnv "TASTY_NUM_THREADS" "1" True
-- We manipulate global state via the working directory and
-- the environment so running tests in parallel will cause trouble.
yarnPath : damlTypesPath : args <- getArgs
damlc <- locateRunfiles (mainWorkspace </> "compiler" </> "damlc" </> exe "damlc")
daml2ts <- locateRunfiles (mainWorkspace </> "language-support" </> "ts" </> "codegen" </> exe "daml2ts")
davl <- locateRunfiles ("davl" </> "released")
yarnPath : damlTypesPath : args <- getArgs
yarn <- locateRunfiles (mainWorkspace </> yarnPath)
damlTypes <- (</> damlTypesPath) <$> getCurrentDirectory
damlTypes <- locateRunfiles (mainWorkspace </> damlTypesPath)
davl <- locateRunfiles ("davl" </> "released")
-- TODO (SF,2020-03-24): Factor out 'withEnv' from
-- 'DA/DamlAssistant/Tests.hs' into a library function and use it here.
oldPath <- getSearchPath
setEnv "PATH" (intercalate [searchPathSeparator] $ takeDirectory yarn : oldPath) True
withArgs args (defaultMain $ tests damlTypes yarn damlc daml2ts davl)
-- It may help to keep in mind for the following tests, this quick
@ -85,8 +95,8 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
step "daml build..."
buildProject ["-o", ".daml" </> "dist" </> "elmo-1.0.dar"]
step "daml2ts..."
setupWorkspace
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, elmoDar] ++ ["-o", daml2tsDir, "-p", here </> "package.json"]) ""
copyDirectory damlTypes "daml-types"
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, elmoDar] ++ ["-o", daml2tsDir]) ""
assertBool "A duplicate name for different packages error was expected." (exitCode /= ExitSuccess && isJust (stripInfix "Duplicate name 'grover-1.0' for different packages detected" err))
, testCaseSteps "Different name, same package test" $ \step -> withTempDir $ \here -> do
@ -133,47 +143,18 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
buildProject []
withCurrentDirectory here $ do
step "daml2ts..."
setupWorkspace
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, superGroverDar] ++ ["-o", daml2tsDir, "-p", here </> "package.json"]) ""
copyDirectory damlTypes "daml-types"
writePackageJson
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar, superGroverDar] ++ ["-o", daml2tsDir]) ""
assertBool "A different names for same package error was expected." (exitCode /= ExitSuccess && isJust (stripInfix "Different names ('grover-1.0' and 'super-grover-1.0') for the same package detected" err))
, testCaseSteps "Bad package.json test" $ \step -> withTempDir $ \here -> do
let grover = here </> "grover"
groverDaml = grover </> "daml"
daml2tsDir = here </> "daml2ts"
groverDar = grover </> ".daml" </> "dist" </> "grover-1.0.dar"
createDirectoryIfMissing True groverDaml
withCurrentDirectory grover $ do
writeFileUTF8 (groverDaml </> "Grover.daml") $ unlines
[ "module Grover where"
, "template Grover"
, " with puppeteer : Party"
, " where"
, " signatory puppeteer"
, " choice Grover_GoSuper: ContractId Grover"
, " controller puppeteer"
, " do"
, " return self"
]
writeDamlYaml "grover" ["Grover"] ["daml-prim", "daml-stdlib"] Nothing
step "daml build..."
buildProject []
withCurrentDirectory here $ do
step "daml2ts..."
setupWorkspace
writeFileUTF8 (here </> "package.json") .
replace " \"@daml/types\": \"file:daml-types\""
" \"@daml/types\": \"file:daml-types\","
=<< readFileUTF8' (here </> "package.json")
(exitCode, _, err) <- readProcessWithExitCode daml2ts ([groverDar] ++ ["-o", daml2tsDir]) ""
assertBool "An error decoding package.json was expected." (exitCode /= ExitSuccess && isJust (stripInfix "'package.json' : Error in $: Failed reading: satisfy. Expecting object value)" err))
, testCaseSteps "Same package, same name test" $ \step -> withTempDir $ \here -> do
let grover = here </> "grover"
groverDaml = grover </> "daml"
daml2tsDir = here </> "daml2ts"
groverTs = daml2tsDir </> "grover-1.0"
groverTsSrc = groverTs </> "src"
groverTsLib = groverTs </> "lib"
groverDar = grover </> ".daml" </> "dist" </> "grover-1.0.dar"
createDirectoryIfMissing True groverDaml
withCurrentDirectory grover $ do
@ -193,55 +174,65 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
buildProject []
withCurrentDirectory here $ do
step "daml2ts..."
setupWorkspace
daml2tsProject [groverDar, groverDar] daml2tsDir (here </> "package.json")
writePackageJson
copyDirectory damlTypes "daml-types"
daml2tsProject [groverDar, groverDar] daml2tsDir
assertFileExists (groverTsSrc </> "Grover.ts")
assertFileExists (groverTsLib </> "Grover.js")
assertFileExists (groverTsLib </> "Grover.d.ts")
assertFileExists (groverTsSrc </> "packageId.ts")
assertFileExists (groverTsLib </> "packageId.js")
assertFileExists (groverTsLib </> "packageId.d.ts")
, testCaseSteps "DAVL test" $ \step -> withTempDir $ \here -> do
let daml2tsDir = here </> "daml2ts"
withCurrentDirectory here $ do
copyDirectory damlTypes "daml-types"
step "daml2ts..."
-- Call daml2ts once without a 'package.json'.
writePackageJson
callProcessSilent daml2ts $
[ davl </> "davl-v4.dar"
, davl </> "davl-v5.dar"
, davl </> "davl-upgrade-v4-v5.dar" ] ++
["-o", daml2tsDir]
assertFileExists (here </> "package.json")
-- Overwrite the 'package.json' that daml2ts generated because
-- we need to adjust module resolution for @daml/types and
-- @daml/ledger.
setupWorkspace
-- Call daml2ts again which will this time update 'package.json'.
callProcessSilent daml2ts $
[ davl </> "davl-v4.dar"
, davl </> "davl-v5.dar"
, davl </> "davl-upgrade-v4-v5.dar" ] ++
["-o", daml2tsDir] -- There's no need to pass '-p
-- here/package.json' but we could and it would mean the same.
assertFileExists (daml2tsDir </> "davl-0.0.4" </> "src" </> "DAVL.ts")
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "src" </> "DAVL.ts")
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "src" </> "Upgrade.ts")
step "yarn install..."
yarnProject ["install"]
step "yarn workspaces run build..."
yarnProject ["workspaces", "run", "build"]
assertFileExists (daml2tsDir </> "davl-0.0.4" </> "lib" </> "DAVL.js")
assertFileExists (daml2tsDir </> "davl-0.0.4" </> "lib" </> "DAVL.d.ts")
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "src" </> "DAVL.ts")
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "lib" </> "DAVL.js")
assertFileExists (daml2tsDir </> "davl-0.0.5" </> "lib" </> "DAVL.d.ts")
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "src" </> "Upgrade.ts")
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "lib" </> "Upgrade.js")
step "yarn workspaces run lint..."
yarnProject ["workspaces", "run", "lint"]
]
assertFileExists (daml2tsDir </> "davl-upgrade-v4-v5-0.0.5" </> "lib" </> "Upgrade.d.ts")
step "eslint..."
withCurrentDirectory daml2tsDir $ do
pkgs <- (\\ ["package.json", "node_modules"]) <$> listDirectory daml2tsDir
BSL.writeFile "package.json" $ encode (
object
[ "private" .= True
, "devDependencies" .= HMS.fromList
([ ("eslint", "^6.7.2")
, ("@typescript-eslint/eslint-plugin", "2.11.0")
, ("@typescript-eslint/parser", "2.11.0")
] :: [(T.Text, T.Text)]
)
, "dependencies" .= HMS.fromList
([ ("@daml/types", "file:../daml-types")
, ("@mojotech/json-type-validation", "^3.1.0")
] :: [(T.Text, T.Text)])
, "workspaces" .= pkgs
, "name" .= ("daml2ts" :: T.Text)
, "version" .= ("0.0.0" :: T.Text)
])
callProcessSilent yarn ["install", "--pure-lockfile"]
callProcessSilent yarn ["workspaces", "run", "lint"]
]
where
buildProject :: [String] -> IO ()
buildProject args = callProcessSilent damlc (["build"] ++ args)
daml2tsProject :: [FilePath] -> FilePath -> FilePath -> IO ()
daml2tsProject dars outDir packageJson = callProcessSilent daml2ts $ dars ++ ["-o", outDir, "-p", packageJson]
yarnProject :: [String] -> IO ()
yarnProject args = callProcessSilent yarn args
daml2tsProject :: [FilePath] -> FilePath -> IO ()
daml2tsProject dars outDir = callProcessSilent daml2ts $ dars ++ ["-o", outDir]
callProcessSilent :: FilePath -> [String] -> IO ()
callProcessSilent cmd args = do
@ -252,19 +243,6 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
hPutStrLn stderr $ unlines ["stderr:", err]
exitFailure
setupWorkspace :: IO ()
setupWorkspace = do
copyDirectory damlTypes "daml-types"
writeFileUTF8 "package.json" $ unlines
[ "{"
, " \"private\": true,"
, " \"workspaces\": [],"
, " \"resolutions\": {"
, " \"@daml/types\": \"file:daml-types\""
, " }"
, "}"
]
writeDamlYaml :: String -> [String] -> [String] -> Maybe LF.Version -> IO ()
writeDamlYaml mainPackageName exposedModules dependencies mbLfVersion =
writeFileUTF8 "daml.yaml" $ unlines $
@ -278,5 +256,14 @@ tests damlTypes yarn damlc daml2ts davl = testGroup "daml2ts tests"
[" - " ++ dependency | dependency <- dependencies] ++
["build-options: [--target=" <> LF.renderVersion ver <> "]" | Just ver <- [mbLfVersion]]
writePackageJson :: IO ()
writePackageJson = BSL.writeFile "package.json" $ encode packageJson
where
packageJson = object
[ "private" .= True
, "workspaces" .= (["daml2ts"] :: [T.Text])
, "resolutions" .= HMS.fromList ([("@daml/types", "file:daml-types")] :: [(T.Text, T.Text)])
]
assertFileExists :: FilePath -> IO ()
assertFileExists file = doesFileExist file >>= assertBool (file ++ " was not created")

View File

@ -5,8 +5,7 @@
"description": "Tests exercising '@daml.js/build-and-lint-1.0.0",
"license": "Apache-2.0",
"dependencies": {
"@daml/ledger": "0.0.0",
"@daml/types": "0.0.0",
"@daml/ledger": "file:../daml-ledger",
"@daml.js/build-and-lint-1.0.0": "file:../daml2ts/build-and-lint-1.0.0",
"p-event": "^4.1.0"
},

View File

@ -1,10 +1,10 @@
{
"private": true,
"workspaces": [
"build-and-lint-test"
"build-and-lint-test",
"daml2ts"
],
"resolutions": {
"@daml/types": "file:daml-types",
"@daml/ledger": "file:daml-ledger"
"@daml/types": "file:daml-types"
}
}