From 6cd5280867aa2caf1ef2bf8f2a57a3a92a4b4d7f Mon Sep 17 00:00:00 2001 From: Shayne Fletcher Date: Tue, 14 Apr 2020 12:14:49 -0400 Subject: [PATCH] add support for daml2js to write daml-ledger code (#5550) changelog_begin changelog_end --- .../src/DA/Daml/Assistant/IntegrationTests.hs | 6 +- language-support/ts/codegen/README.md | 5 +- .../ts/codegen/src/TsCodeGenMain.hs | 56 ++++++++++--------- language-support/ts/codegen/tests/BUILD.bazel | 3 +- .../ts/codegen/tests/src/DA/Test/Daml2js.hs | 6 +- .../build-and-lint-test/src/__tests__/test.ts | 5 +- .../ts/codegen/tests/ts/package.json | 8 ++- 7 files changed, 51 insertions(+), 38 deletions(-) diff --git a/daml-assistant/integration-tests/src/DA/Daml/Assistant/IntegrationTests.hs b/daml-assistant/integration-tests/src/DA/Daml/Assistant/IntegrationTests.hs index 90a559539b..40e6d3e485 100644 --- a/daml-assistant/integration-tests/src/DA/Daml/Assistant/IntegrationTests.hs +++ b/daml-assistant/integration-tests/src/DA/Daml/Assistant/IntegrationTests.hs @@ -535,7 +535,7 @@ codegenTests codegenDir = testGroup "daml codegen" ( outDir = projectDir "generated" lang when (lang == "js") $ do let workspaces = Workspaces [makeRelative codegenDir outDir] - setupYarnEnv codegenDir workspaces [DamlTypes] + setupYarnEnv codegenDir workspaces [DamlTypes, DamlLedger] callCommandSilent $ unwords [ "daml", "codegen", lang , darFile ++ maybe "" ("=" ++) namespace @@ -558,7 +558,7 @@ createDamlAppTests = testGroup "create-daml-app" [gettingStartedGuideTest | not step "Build DAML model for base application" callCommandSilent "daml build" step "Set up TypeScript libraries and Yarn workspaces for codegen" - setupYarnEnv tmpDir (Workspaces ["create-daml-app/daml.js"]) [DamlTypes] + setupYarnEnv tmpDir (Workspaces ["create-daml-app/daml.js"]) [DamlTypes, DamlLedger] step "Run JavaScript codegen" callCommandSilent "daml codegen js -o daml.js .daml/dist/create-daml-app-0.1.0.dar" assertFileDoesNotExist (cdaDir "ui" "build" "index.html") @@ -589,7 +589,7 @@ createDamlAppTests = testGroup "create-daml-app" [gettingStartedGuideTest | not step "Build the new DAML model" callCommandSilent "daml build" step "Set up TypeScript libraries and Yarn workspaces for codegen again" - setupYarnEnv tmpDir (Workspaces ["create-daml-app/daml.js"]) [DamlTypes] + setupYarnEnv tmpDir (Workspaces ["create-daml-app/daml.js"]) [DamlTypes, DamlLedger] step "Run JavaScript codegen for new DAML model" callCommandSilent "daml codegen js -o daml.js .daml/dist/create-daml-app-0.1.0.dar" withCurrentDirectory (cdaDir "ui") $ do diff --git a/language-support/ts/codegen/README.md b/language-support/ts/codegen/README.md index 8f6477641e..3d6f78dd6d 100644 --- a/language-support/ts/codegen/README.md +++ b/language-support/ts/codegen/README.md @@ -55,13 +55,16 @@ cat > package.json< ([ModuleName], Set.Set PackageId) splitImports imports = let classifyImport (pkgRef, modName) = case pkgRef of @@ -294,8 +295,8 @@ genDefDataType curPkgId conName mod tpls def = -- of each. assocSers = map (\(n, d) -> (n, serFromDef (drop 1) n d)) assocDefDataTypes -- Type of the companion object. - typ' = "daml.Serializable<" <> conName <> "> & {\n" <> - T.concat (map (\n -> " " <> n <> ": daml.Serializable<" <> (conName <.> n) <> ">;\n") assocNames) <> + typ' = "damlTypes.Serializable<" <> conName <> "> & {\n" <> + T.concat (map (\n -> " " <> n <> ": damlTypes.Serializable<" <> (conName <.> n) <> ">;\n") assocNames) <> " }" -- Body of the companion object. body = map (" " <>) $ @@ -312,7 +313,7 @@ genDefDataType curPkgId conName mod tpls def = typeDesc = "" : [" | '" <> cons <> "'" | cons <- cs] -- The complete definition of the companion object. serDesc = - ["export const " <> conName <> ": daml.Serializable<" <> conName <> "> " <> + ["export const " <> conName <> ": damlTypes.Serializable<" <> conName <> "> " <> "& { readonly keys: " <> conName <> "[] } & { readonly [e in " <> conName <> "]: e } = {"] ++ [" " <> cons <> ": '" <> cons <> "'," | cons <- cs] ++ [" keys: [" <> T.concat ["'" <> cons <> "'," | cons <- cs] <> "],"] ++ @@ -356,8 +357,8 @@ genDefDataType curPkgId conName mod tpls def = (conName <.> "Key", "() => " <> snd (genType (moduleName mod) keyType) <> ".decoder()", Set.setOf typeModuleRef keyType) templateId = unPackageId curPkgId <> ":" <> T.intercalate "." (unModuleName (moduleName mod)) <> ":" <> conName dict = - ["export const " <> conName <> ": daml.Template<" <> conName <> ", " <> keyTypeTs <> ", '" <> templateId <> "'> & {"] ++ - [" " <> x <> ": daml.Choice<" <> conName <> ", " <> t <> ", " <> rtyp <> ", " <> keyTypeTs <> ">;" | (x, t, rtyp, _) <- chcs] ++ + ["export const " <> conName <> ": damlTypes.Template<" <> conName <> ", " <> keyTypeTs <> ", '" <> templateId <> "'> & {"] ++ + [" " <> x <> ": damlTypes.Choice<" <> conName <> ", " <> t <> ", " <> rtyp <> ", " <> keyTypeTs <> ">;" | (x, t, rtyp, _) <- chcs] ++ ["} = {" ] ++ [" templateId: '" <> templateId <> "'," @@ -372,9 +373,9 @@ genDefDataType curPkgId conName mod tpls def = -- We'd write, -- " resultDecoder: " <> rser <> ".decoder" -- here but, consider the following scenario: - -- export const Person: daml.Template... + -- export const Person: damlTypes.Template... -- = { ... - -- Birthday: { resultDecoder: daml.ContractId(Person).decoder, ... } + -- Birthday: { resultDecoder: damlTypes.ContractId(Person).decoder, ... } -- ... -- } -- This gives rise to "error TS2454: Variable 'Person' is used before being assigned." @@ -391,7 +392,7 @@ genDefDataType curPkgId conName mod tpls def = , "}" ]) (tplKey tpl) registrations = - ["daml.registerTemplate(" <> conName <> ");"] + ["damlTypes.registerTemplate(" <> conName <> ");"] refs = Set.unions (fieldRefs ++ keyRefs : chcRefs) in ((makeType typeDesc, dict ++ associatedTypes ++ registrations), refs) @@ -400,10 +401,10 @@ genDefDataType curPkgId conName mod tpls def = typeParams | null paramNames = "" | otherwise = "<" <> T.intercalate ", " paramNames <> ">" - serParam paramName = paramName <> ": daml.Serializable<" <> paramName <> ">" + serParam paramName = paramName <> ": damlTypes.Serializable<" <> paramName <> ">" serHeader - | null paramNames = ": daml.Serializable<" <> conName <> "> =" - | otherwise = " = " <> typeParams <> "(" <> T.intercalate ", " (map serParam paramNames) <> "): daml.Serializable<" <> conName <> typeParams <> "> =>" + | null paramNames = ": damlTypes.Serializable<" <> conName <> "> =" + | otherwise = " = " <> typeParams <> "(" <> T.intercalate ", " (map serParam paramNames) <> "): damlTypes.Serializable<" <> conName <> typeParams <> "> =>" makeType = onHead (\x -> "export type " <> conName <> typeParams <> " = " <> x) makeSer serDesc = ["export const " <> conName <> serHeader <> " ({"] ++ @@ -438,36 +439,36 @@ genType curModName = go where go = \case TVar v -> dupe (unTypeVarName v) - TUnit -> ("{}", "daml.Unit") - TBool -> ("boolean", "daml.Bool") - TInt64 -> dupe "daml.Int" - TDecimal -> dupe "daml.Decimal" + TUnit -> ("{}", "damlTypes.Unit") + TBool -> ("boolean", "damlTypes.Bool") + TInt64 -> dupe "damlTypes.Int" + TDecimal -> dupe "damlTypes.Decimal" TNumeric (TNat n) -> ( - "daml.Numeric" - , "daml.Numeric(" <> T.pack (show (fromTypeLevelNat n :: Integer)) <> ")" + "damlTypes.Numeric" + , "damlTypes.Numeric(" <> T.pack (show (fromTypeLevelNat n :: Integer)) <> ")" ) - TText -> ("string", "daml.Text") - TTimestamp -> dupe "daml.Time" - TParty -> dupe "daml.Party" - TDate -> dupe "daml.Date" + TText -> ("string", "damlTypes.Text") + TTimestamp -> dupe "damlTypes.Time" + TParty -> dupe "damlTypes.Party" + TDate -> dupe "damlTypes.Date" TList t -> let (t', ser) = go t in - (t' <> "[]", "daml.List(" <> ser <> ")") + (t' <> "[]", "damlTypes.List(" <> ser <> ")") TOptional t -> let (t', ser) = go t in - ("daml.Optional<" <> t' <> ">", "daml.Optional(" <> ser <> ")") + ("damlTypes.Optional<" <> t' <> ">", "damlTypes.Optional(" <> ser <> ")") TTextMap t -> let (t', ser) = go t in - ("{ [key: string]: " <> t' <> " }", "daml.TextMap(" <> ser <> ")") + ("{ [key: string]: " <> t' <> " }", "damlTypes.TextMap(" <> ser <> ")") TUpdate _ -> error "IMPOSSIBLE: Update not serializable" TScenario _ -> error "IMPOSSIBLE: Scenario not serializable" TContractId t -> let (t', ser) = go t in - ("daml.ContractId<" <> t' <> ">", "daml.ContractId(" <> ser <> ")") + ("damlTypes.ContractId<" <> t' <> ">", "damlTypes.ContractId(" <> ser <> ")") TConApp con ts -> let (con', ser) = genTypeCon curModName con (ts', sers) = unzip (map go ts) @@ -552,6 +553,7 @@ packageJsonDependencies :: SdkVersion -> Scope -> [Dependency] -> Value packageJsonDependencies sdkVersion (Scope scope) dependencies = object $ [ "@mojotech/json-type-validation" .= jtvVersion , "@daml/types" .= versionToText sdkVersion + , "@daml/ledger" .= versionToText sdkVersion ] ++ [ (scope <> "/" <> pkgName) .= ("file:../" <> pkgName) | Dependency pkgName <- dependencies ] diff --git a/language-support/ts/codegen/tests/BUILD.bazel b/language-support/ts/codegen/tests/BUILD.bazel index 70aebcd31d..ddc50d1a5c 100644 --- a/language-support/ts/codegen/tests/BUILD.bazel +++ b/language-support/ts/codegen/tests/BUILD.bazel @@ -107,7 +107,7 @@ sh_test( deps = [ "@bazel_tools//tools/bash/runfiles", ], -) if is_linux else None +) if not is_windows else None da_haskell_library( name = "daml2js-test-helpers", @@ -147,6 +147,7 @@ da_haskell_test( "//:yarn", "//compiler/damlc", "//language-support/ts/codegen:daml2js", + "//language-support/ts/daml-ledger:npm_package", "//language-support/ts/daml-types:npm_package", "@davl//:released/davl-upgrade-v4-v5.dar", "@davl//:released/davl-v4.dar", diff --git a/language-support/ts/codegen/tests/src/DA/Test/Daml2js.hs b/language-support/ts/codegen/tests/src/DA/Test/Daml2js.hs index ff3b1771a7..7c64a18f1c 100644 --- a/language-support/ts/codegen/tests/src/DA/Test/Daml2js.hs +++ b/language-support/ts/codegen/tests/src/DA/Test/Daml2js.hs @@ -228,7 +228,9 @@ tests yarn damlc daml2js davl = testGroup "daml2js tests" , "@typescript-eslint/parser" .= typescriptEslintVersion ] , "workspaces" .= pkgs - , "resolutions" .= object ["@daml/types" .= ("file:../daml-types" :: T.Text)] + , "resolutions" .= object + [ "@daml/types" .= ("file:../daml-types" :: T.Text) + , "@daml/ledger" .= ("file:../daml-ledger" :: T.Text)] ] BSL.writeFile ".eslintrc.json" $ encode $ object @@ -252,7 +254,7 @@ tests yarn damlc daml2js davl = testGroup "daml2js tests" where setupYarnEnvironment :: IO () setupYarnEnvironment = do - setupYarnEnv "." (Workspaces ["daml2js"]) [DamlTypes] + setupYarnEnv "." (Workspaces ["daml2js"]) [DamlTypes, DamlLedger] buildProject :: [String] -> IO () buildProject args = callProcessSilent damlc (["build"] ++ args) diff --git a/language-support/ts/codegen/tests/ts/build-and-lint-test/src/__tests__/test.ts b/language-support/ts/codegen/tests/ts/build-and-lint-test/src/__tests__/test.ts index 873deca632..0a76f8db76 100644 --- a/language-support/ts/codegen/tests/ts/build-and-lint-test/src/__tests__/test.ts +++ b/language-support/ts/codegen/tests/ts/build-and-lint-test/src/__tests__/test.ts @@ -26,6 +26,7 @@ const BOB_TOKEN = computeToken(BOB_PARTY); const SANDBOX_PORT = 6865; const SANDBOX_PORT_FILE = 'sandbox.port'; const JSON_API_PORT = 7575; +const JSON_API_PORT_FILE = 'json-api.port'; const HTTP_BASE_URL = `http://localhost:${JSON_API_PORT}/`; let sandboxProcess: ChildProcess | undefined = undefined; @@ -57,8 +58,8 @@ beforeAll(async () => { console.log('Sandbox up'); jsonApiProcess = await spawnJvmAndWaitOn( getEnv('JSON_API'), - ['--ledger-host', 'localhost', '--ledger-port', `${SANDBOX_PORT}`,'--http-port', `${JSON_API_PORT}`, '--websocket-config', 'heartBeatPer=1'], - `tcp:localhost:${JSON_API_PORT}`, + ['--ledger-host', 'localhost', '--ledger-port', `${SANDBOX_PORT}`, '--port-file', JSON_API_PORT_FILE, '--http-port', `${JSON_API_PORT}`, '--websocket-config', 'heartBeatPer=1'], + `file:${JSON_API_PORT_FILE}`, ) console.log('JSON API up'); }); diff --git a/language-support/ts/codegen/tests/ts/package.json b/language-support/ts/codegen/tests/ts/package.json index 2c3b8b260f..8329bea1b3 100644 --- a/language-support/ts/codegen/tests/ts/package.json +++ b/language-support/ts/codegen/tests/ts/package.json @@ -1,7 +1,11 @@ { "private": true, - "workspaces": ["daml2js", "build-and-lint-test"], + "workspaces": [ + "daml2js", + "build-and-lint-test" + ], "resolutions": { - "@daml/types": "file:daml-types" + "@daml/types": "file:daml-types", + "@daml/ledger": "file:daml-ledger" } }