packages feed

hydra-typescript 0.17.2 → 0.17.3

raw patch · 3 files changed

+94/−92 lines, 3 filesdep ~hydra-kernelPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: hydra-kernel

API changes (from Hackage documentation)

Files

hydra-typescript.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           hydra-typescript-version:        0.17.2+version:        0.17.3 synopsis:       Hydra's TypeScript coder: emit TypeScript source from Hydra modules description:    Hydra is an implementation of the LambdaGraph data model, which takes advantage of an isomorphism between labeled hypergraphs and typed lambda calculus: in Hydra, "graphs are programs, and programs are graphs". TypeScript support for Hydra category:       Data@@ -40,6 +40,6 @@   build-depends:       base >=4.19.0 && <4.22     , containers >=0.6.7 && <0.8-    , hydra-kernel ==0.17.2+    , hydra-kernel ==0.17.3     , scientific >=0.3.7 && <0.4   default-language: Haskell2010
src/main/haskell/Hydra/TypeScript/Coder.hs view
@@ -176,7 +176,7 @@           bigIntCall = \txt -> tsCall (tsExprIdent "BigInt") [                 strLit txt]       in case lit of-        Core.LiteralBinary v0 -> strLit (Literals.binaryToString v0)+        Core.LiteralBinary v0 -> strLit (Literals.binaryToBase64 v0)         Core.LiteralBoolean v0 -> boolLit v0         Core.LiteralDecimal v0 -> numLit (Literals.bigintToInt64 (Literals.decimalToBigint v0))         Core.LiteralString v0 -> strLit v0@@ -239,7 +239,7 @@             varExpr =                     Optionals.cases (Names.moduleNameOf v0) (tsExprIdent local) (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) (tsExprIdent local) (                       let nsSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName ns))-                          alias = Strings.cat2 "$mod_" (Strings.intercalate "_" nsSegs)+                          alias = Strings.concat2 "$mod_" (Strings.join "_" nsSegs)                       in (tsMember (tsExprIdent alias) local)))         in (Optionals.cases (Lexical.lookupPrimitive g v0) varExpr (\prim ->           let isZeroArityEffect =@@ -271,7 +271,7 @@                       let idx = Pairs.first acc                           pats = Pairs.second acc                           raw = Names.localNameOf pn-                          uniq = Logic.ifElse (Equality.equal raw "_") (Strings.cat2 "_" (Literals.showInt32 idx)) raw+                          uniq = Logic.ifElse (Equality.equal raw "_") (Strings.concat2 "_" (Literals.showInt32 idx)) raw                           pat = tsTypedIdent (Formatting.sanitizeWithUnderscores Language.typeScriptReservedWords uniq) Syntax.TypeExpressionAny                       in (Math.add idx 1, (Lists.concat2 pats [                         pat]))) (0, []) fsLParams@@ -298,14 +298,14 @@               let headExpr = encodeTerm cx g currentNs headTerm               in headExpr) (               let fname = Formatting.sanitizeWithUnderscores Language.typeScriptReservedWords (Core.unName (Core.projectionFieldName v1))-                  firstA = Optionals.fromOptional (tsExprIdent "undefined") (Lists.maybeHead encArgs)+                  firstA = Optionals.withDefault (tsExprIdent "undefined") (Lists.head encArgs)                   restA = Lists.drop 1 encArgs                   fieldExpr = tsMember firstA fname               in (Logic.ifElse (Lists.null restA) fieldExpr (tsCall fieldExpr restA)))             Core.TermUnwrap _ -> Logic.ifElse (Lists.null encArgs) (               let headExpr = encodeTerm cx g currentNs headTerm               in headExpr) (-              let firstA = Optionals.fromOptional (tsExprIdent "undefined") (Lists.maybeHead encArgs)+              let firstA = Optionals.withDefault (tsExprIdent "undefined") (Lists.head encArgs)                   restA = Lists.drop 1 encArgs                   valueExpr = tsMember firstA "value"               in (Logic.ifElse (Lists.null restA) valueExpr (tsCall valueExpr restA)))@@ -511,8 +511,8 @@           let lname = Formatting.capitalize (Names.localNameOf v0)           in (Optionals.cases (Names.moduleNameOf v0) (Right (tsNamedType lname)) (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) (Right (tsNamedType lname)) (             let nsSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName ns))-                typeAlias = Strings.cat2 "$type_" (Strings.intercalate "_" nsSegs)-            in (Right (tsNamedType (Strings.cat [+                typeAlias = Strings.concat2 "$type_" (Strings.join "_" nsSegs)+            in (Right (tsNamedType (Strings.concat [               typeAlias,               ".",               lname]))))))@@ -596,7 +596,7 @@ -- | Keep only names whose module differs from the current module's filterNonLocalNames :: Packaging.ModuleName -> S.Set Core.Name -> S.Set Core.Name filterNonLocalNames currentNs names =-    Sets.fromList (Optionals.cat (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\nameNs -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName nameNs)) Nothing (Just n))) (Sets.toList names)))+    Sets.fromList (Optionals.givens (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\nameNs -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName nameNs)) Nothing (Just n))) (Sets.toList names)))  -- | Walk an application spine, returning the innermost head term and its arguments in application order flattenApplication :: Core.Term -> (Core.Term, [Core.Term])@@ -671,7 +671,7 @@ importsToText kind currentNs names =        let pairs =-              Optionals.cat (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) Nothing (Just (ns, n)))) (Sets.toList names))+              Optionals.givens (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) Nothing (Just (ns, n)))) (Sets.toList names))           transformLocal =                   \s -> Logic.ifElse (Equality.equal kind "type") (Formatting.capitalize s) (Formatting.sanitizeWithUnderscores Language.typeScriptReservedWords s)           importKeyword = Logic.ifElse (Equality.equal kind "type") "import type" "import"@@ -680,30 +680,31 @@                     let ns = Pairs.first p                         n = Pairs.second p                         local = transformLocal (Names.localNameOf n)-                        existing = Optionals.fromOptional [] (Maps.lookup ns acc)+                        existing = Optionals.withDefault [] (Maps.lookup ns acc)                     in (Maps.insert ns (Lists.cons local existing) acc)) Maps.empty pairs           currentSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName currentNs))           currentDepth = Lists.length currentSegs           currentIsTest =-                  Logic.and (Logic.not (Lists.null currentSegs)) (Equality.equal (Optionals.fromOptional "" (Lists.maybeHead currentSegs)) "test")-          baseUpPrefix = Logic.ifElse (Equality.equal currentDepth 1) "./" (Strings.cat (Lists.replicate (Math.sub currentDepth 1) "../"))+                  Logic.and (Logic.not (Lists.null currentSegs)) (Equality.equal (Optionals.withDefault "" (Lists.head currentSegs)) "test")+          baseUpPrefix =+                  Logic.ifElse (Equality.equal currentDepth 1) "./" (Strings.concat (Lists.replicate (Math.sub currentDepth 1) "../"))           lines =                   Lists.map (\entry ->                     let ns = Pairs.first entry                         locals = Pairs.second entry                         targetSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName ns))                         targetIsTest =-                                Logic.and (Logic.not (Lists.null targetSegs)) (Equality.equal (Optionals.fromOptional "" (Lists.maybeHead targetSegs)) "test")+                                Logic.and (Logic.not (Lists.null targetSegs)) (Equality.equal (Optionals.withDefault "" (Lists.head targetSegs)) "test")                         targetPathSegs =-                                Logic.ifElse (Logic.and (Equality.equal (Optionals.fromOptional "" (Lists.maybeHead targetSegs)) "lib") (Logic.not (Equality.equal (Packaging.unModuleName ns) "hydra.lib.defaults"))) (Lists.concat2 [+                                Logic.ifElse (Equality.equal (Optionals.withDefault "" (Lists.head targetSegs)) "lib") (Lists.concat2 [                                   "overlay",                                   "typescript"] targetSegs) targetSegs-                        targetPath = Strings.intercalate "/" targetPathSegs+                        targetPath = Strings.join "/" targetPathSegs                         upPrefix =-                                Logic.ifElse (Logic.and currentIsTest (Logic.not targetIsTest)) (Strings.cat2 baseUpPrefix "../../../main/typescript/hydra/") baseUpPrefix-                        nsSlug = Strings.intercalate "_" targetSegs-                        moduleAlias = Logic.ifElse (Equality.equal kind "type") (Strings.cat2 "$type_" nsSlug) (Strings.cat2 "$mod_" nsSlug)-                    in (Strings.cat [+                                Logic.ifElse (Logic.and currentIsTest (Logic.not targetIsTest)) (Strings.concat2 baseUpPrefix "../../../main/typescript/hydra/") baseUpPrefix+                        nsSlug = Strings.join "_" targetSegs+                        moduleAlias = Logic.ifElse (Equality.equal kind "type") (Strings.concat2 "$type_" nsSlug) (Strings.concat2 "$mod_" nsSlug)+                    in (Strings.concat [                       importKeyword,                       " * as ",                       moduleAlias,@@ -711,7 +712,7 @@                       upPrefix,                       targetPath,                       ".js\";\n"])) (Maps.toList grouped)-      in (Strings.cat lines)+      in (Strings.concat lines)  -- | Look up a primitive by name and return its per-parameter laziness flags in parameter order lazyFlagsForPrimitive :: Graph.Graph -> Core.Name -> [Bool]@@ -761,25 +762,25 @@                   Lists.foldl (\acc -> \td -> Sets.union acc (collectTermImports currentNs (Packaging.termDefinitionBody td))) Sets.empty termDefs           typeImportsBlock = importsToText "type" currentNs typeImports           termImportsBlock = importsToText "value" currentNs termImports-          importsBlock = Strings.cat2 typeImportsBlock termImportsBlock+          importsBlock = Strings.concat2 typeImportsBlock termImportsBlock       in (Eithers.bind (Eithers.mapList (encodeTypeDefinition cx g currentNs) typeDefs) (\typeItems ->         let termItems = Lists.map (encodeTermDefinition cx g currentNs) termDefs             allItems = Lists.concat2 typeItems termItems             mModuleDoc = Optionals.bind (Packaging.moduleMetadata mod) (\em -> Packaging.entityMetadataDescription em)-            moduleDocText = Optionals.cases mModuleDoc "" (\d -> Strings.cat2 (Serde.toTypeScriptComments d []) "\n\n")-            header = Strings.cat2 "// Note: this is an automatically generated file. Do not edit.\n\n" moduleDocText+            moduleDocText = Optionals.cases mModuleDoc "" (\d -> Strings.concat2 (Serde.toTypeScriptComments d []) "\n\n")+            header = Strings.concat2 "// Note: this is an automatically generated file. Do not edit.\n\n" moduleDocText             renderItem =                     \docAndItem ->                       let mdoc = Pairs.first docAndItem                           item = Pairs.second docAndItem                           itemText = printModuleItem item-                      in (Optionals.cases mdoc itemText (\d -> Strings.cat [+                      in (Optionals.cases mdoc itemText (\d -> Strings.concat [                         Serde.toTypeScriptComments d [],                         "\n",                         itemText]))-            body = Strings.intercalate "\n\n" (Lists.map renderItem allItems)+            body = Strings.join "\n\n" (Lists.map renderItem allItems)             filePath = Names.moduleNameToFilePath Util.CaseConventionCamel (File.FileExtension "ts") (Packaging.moduleName mod)-        in (Right (Maps.singleton filePath (Strings.cat [+        in (Right (Maps.singleton filePath (Strings.concat [           header,           importsBlock,           (Logic.ifElse (Equality.equal importsBlock "") "" "\n"),@@ -794,15 +795,15 @@           params = printTypeParameterList (Syntax.interfaceDeclarationTypeParameters decl)           exts = Syntax.interfaceDeclarationExtends decl           extClause =-                  Logic.ifElse (Lists.null exts) "" (Strings.cat2 " extends " (Strings.intercalate ", " (Lists.map printTypeExpression exts)))+                  Logic.ifElse (Lists.null exts) "" (Strings.concat2 " extends " (Strings.join ", " (Lists.map printTypeExpression exts)))           members = Syntax.interfaceDeclarationMembers decl-          renderMember = \ps -> Strings.intercalate "\n  " (Strings.lines (printPropertySignature ps))+          renderMember = \ps -> Strings.join "\n  " (Strings.lines (printPropertySignature ps))           body =-                  Logic.ifElse (Lists.null members) "" (Strings.cat [+                  Logic.ifElse (Lists.null members) "" (Strings.concat [                     "\n  ",-                    (Strings.intercalate ";\n  " (Lists.map renderMember members)),+                    (Strings.join ";\n  " (Lists.map renderMember members)),                     ";\n"])-      in (Strings.cat [+      in (Strings.concat [         "export interface ",         name,         params,@@ -838,13 +839,13 @@        let mcomments = Syntax.propertySignatureComments ps           line =-                  Strings.cat [+                  Strings.concat [                     Logic.ifElse (Syntax.propertySignatureReadonly ps) "readonly " "",                     (Syntax.unIdentifier (Syntax.propertySignatureName ps)),                     (Logic.ifElse (Syntax.propertySignatureOptional ps) "?" ""),                     ": ",                     (printTypeExpression (Syntax.propertySignatureType ps))]-      in (Optionals.cases mcomments line (\dc -> Strings.cat [+      in (Optionals.cases mcomments line (\dc -> Strings.concat [         Serde.toTypeScriptComments (Syntax.documentationCommentDescription dc) (Syntax.documentationCommentTags dc),         "\n",         line]))@@ -856,7 +857,7 @@       let name = Syntax.unIdentifier (Syntax.typeAliasDeclarationName decl)           params = printTypeParameterList (Syntax.typeAliasDeclarationTypeParameters decl)           rhs = printTypeExpression (Syntax.typeAliasDeclarationType decl)-      in (Strings.cat [+      in (Strings.concat [         "export type ",         name,         params,@@ -870,28 +871,28 @@     case t of       Syntax.TypeExpressionIdentifier v0 -> Syntax.unIdentifier v0       Syntax.TypeExpressionLiteral v0 -> printLiteral v0-      Syntax.TypeExpressionArray v0 -> Strings.cat [+      Syntax.TypeExpressionArray v0 -> Strings.concat [         "ReadonlyArray<",         (printTypeExpression (Syntax.unArrayTypeExpression v0)),         ">"]-      Syntax.TypeExpressionTuple v0 -> Strings.cat [+      Syntax.TypeExpressionTuple v0 -> Strings.concat [         "readonly [",-        (Strings.intercalate ", " (Lists.map printTypeExpression v0)),+        (Strings.join ", " (Lists.map printTypeExpression v0)),         "]"]-      Syntax.TypeExpressionUnion v0 -> Strings.intercalate " | " (Lists.map printTypeExpression v0)-      Syntax.TypeExpressionIntersection v0 -> Strings.intercalate " & " (Lists.map printTypeExpression v0)-      Syntax.TypeExpressionParameterized v0 -> Strings.cat [+      Syntax.TypeExpressionUnion v0 -> Strings.join " | " (Lists.map printTypeExpression v0)+      Syntax.TypeExpressionIntersection v0 -> Strings.join " & " (Lists.map printTypeExpression v0)+      Syntax.TypeExpressionParameterized v0 -> Strings.concat [         printTypeExpression (Syntax.parameterizedTypeExpressionBase v0),         "<",-        (Strings.intercalate ", " (Lists.map printTypeExpression (Syntax.parameterizedTypeExpressionArguments v0))),+        (Strings.join ", " (Lists.map printTypeExpression (Syntax.parameterizedTypeExpressionArguments v0))),         ">"]-      Syntax.TypeExpressionOptional v0 -> Strings.cat [+      Syntax.TypeExpressionOptional v0 -> Strings.concat [         printTypeExpression v0,         " | undefined"]-      Syntax.TypeExpressionReadonly v0 -> Strings.cat2 "readonly " (printTypeExpression v0)-      Syntax.TypeExpressionObject v0 -> Strings.cat [+      Syntax.TypeExpressionReadonly v0 -> Strings.concat2 "readonly " (printTypeExpression v0)+      Syntax.TypeExpressionObject v0 -> Strings.concat [         "{ ",-        (Strings.intercalate "; " (Lists.map printPropertySignature v0)),+        (Strings.join "; " (Lists.map printPropertySignature v0)),         " }"]       Syntax.TypeExpressionFunction _ -> "((...args: any[]) => any)"       Syntax.TypeExpressionAny -> "any"@@ -906,7 +907,7 @@        let name = Syntax.unIdentifier (Syntax.typeParameterName tp)           constraint = Syntax.typeParameterConstraint tp-      in (Optionals.cases constraint name (\c -> Strings.cat [+      in (Optionals.cases constraint name (\c -> Strings.concat [         name,         " extends ",         (printTypeExpression c)]))@@ -914,9 +915,9 @@ -- | Render a generic parameter list, or the empty string when there are no parameters printTypeParameterList :: [Syntax.TypeParameter] -> String printTypeParameterList tps =-    Logic.ifElse (Lists.null tps) "" (Strings.cat [+    Logic.ifElse (Lists.null tps) "" (Strings.concat [       "<",-      (Strings.intercalate ", " (Lists.map printTypeParameter tps)),+      (Strings.join ", " (Lists.map printTypeParameter tps)),       ">"])  -- | Sanitize a Hydra parameter name into a valid, non-reserved TS identifier@@ -936,7 +937,7 @@                         deps = Lists.filter (\n -> Maps.member n byName) (Sets.toList freeVars)                     in (bname, deps)) bindings           sccs = Sorting.topologicalSortComponents adjacency-      in (Optionals.cat (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))+      in (Optionals.givens (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))  -- | Reorder term definitions so each appears after the intra-module definitions it depends on sortTermDefsTopologically :: t0 -> [Packaging.TermDefinition] -> [Packaging.TermDefinition]@@ -951,7 +952,7 @@                         deps = Lists.filter (\n -> Maps.member n byName) (Sets.toList freeVars)                     in (tname, deps)) tdefs           sccs = Sorting.topologicalSortComponents adjacency-      in (Optionals.cat (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))+      in (Optionals.givens (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))  -- | Strip leading forall quantifiers from a type, returning the innermost body stripForalls :: Core.Type -> Core.Type@@ -1048,14 +1049,14 @@ tsDocEntityRef :: Packaging.EntityReference -> String tsDocEntityRef x =     case x of-      Packaging.EntityReferenceDefinition v0 -> Strings.cat2 "{@link " (Strings.cat2 (case v0 of+      Packaging.EntityReferenceDefinition v0 -> Strings.concat2 "{@link " (Strings.concat2 (case v0 of         Packaging.DefinitionReferencePrimitive v1 -> Names.localNameOf v1         Packaging.DefinitionReferenceTerm v1 -> Names.localNameOf v1         Packaging.DefinitionReferenceType v1 -> Names.localNameOf v1) "}")       Packaging.EntityReferenceModule v0 -> Packaging.unModuleName v0       Packaging.EntityReferencePackage v0 -> Packaging.unPackageName v0-      Packaging.EntityReferenceTermExpr v0 -> Strings.cat2 "`" (Strings.cat2 v0 "`")-      Packaging.EntityReferenceTypeExpr v0 -> Strings.cat2 "`" (Strings.cat2 v0 "`")+      Packaging.EntityReferenceTermExpr v0 -> Strings.concat2 "`" (Strings.concat2 v0 "`")+      Packaging.EntityReferenceTypeExpr v0 -> Strings.concat2 "`" (Strings.concat2 v0 "`")  -- | Identity getter for analyzeFunctionTerm when the environment is a Graph tsEnvGetGraph :: t0 -> t0@@ -1071,9 +1072,9 @@        let escapeChar =               \c -> Logic.ifElse (Equality.equal c 34) "\\\"" (Logic.ifElse (Equality.equal c 92) "\\\\" (Logic.ifElse (Equality.equal c 10) "\\n" (Logic.ifElse (Equality.equal c 13) "\\r" (Logic.ifElse (Equality.equal c 9) "\\t" (Logic.ifElse (Equality.equal c 8) "\\b" (Logic.ifElse (Equality.equal c 12) "\\f" (Strings.fromList (Lists.pure c))))))))-      in (Strings.cat [+      in (Strings.concat [         "\"",-        (Strings.cat (Lists.map escapeChar (Strings.toList s))),+        (Strings.concat (Lists.map escapeChar (Strings.toList s))),         "\""])  -- | A bare identifier expression
src/main/haskell/Hydra/TypeScript/Serde.hs view
@@ -24,6 +24,7 @@ import qualified Hydra.Overlay.Haskell.Lib.Logic as Logic import qualified Hydra.Overlay.Haskell.Lib.Math as Math import qualified Hydra.Overlay.Haskell.Lib.Optionals as Optionals+import qualified Hydra.Overlay.Haskell.Lib.Ordering as Ordering import qualified Hydra.Overlay.Haskell.Lib.Pairs as Pairs import qualified Hydra.Overlay.Haskell.Lib.Strings as Strings import qualified Hydra.Packaging as Packaging@@ -51,7 +52,7 @@ -- | True iff every codepoint is an ASCII digit 0-9, and the list is non-empty allDigits :: [Int] -> Bool allDigits cps =-    Logic.and (Equality.gt (Lists.length cps) 0) (Lists.foldl (\acc -> \c -> Logic.and acc (Logic.and (Equality.gte c 48) (Equality.lte c 57))) True cps)+    Logic.and (Ordering.gt (Lists.length cps) 0) (Lists.foldl (\acc -> \c -> Logic.and acc (Logic.and (Ordering.gte c 48) (Ordering.lte c 57))) True cps)  -- | Convert an array element to an AST expression arrayElementToExpr :: Syntax.ArrayElement -> Ast.Expr@@ -315,25 +316,25 @@           mparamName = Syntax.documentationTagParamName tag           description = Syntax.documentationTagDescription tag           typePart =-                  Optionals.cases mtype "" (\t -> Strings.cat [+                  Optionals.cases mtype "" (\t -> Strings.concat [                     "{",                     (typeExpressionToString t),                     "}"])           paramPart = Optionals.cases mparamName "" (\p -> Syntax.unIdentifier p)           parts =                   [-                    Strings.cat2 "@" name,+                    Strings.concat2 "@" name,                     typePart,                     paramPart,                     description]           nonEmpty = Lists.filter (\p -> Logic.not (Equality.equal p "")) parts-      in (Strings.cat2 " * " (Strings.intercalate " " nonEmpty))+      in (Strings.concat2 " * " (Strings.join " " nonEmpty))  -- | Escape special characters in a string for TypeScript escapeString :: String -> Bool -> String escapeString s singleQuote = -      let replace = \old -> \new_ -> \str -> Strings.intercalate new_ (Strings.splitOn old str)+      let replace = \old -> \new_ -> \str -> Strings.join new_ (Strings.splitOn old str)           s1 = replace "\\" "\\\\" s           s2 = replace "\n" "\\n" s1           s3 = replace "\r" "\\r" s2@@ -602,9 +603,9 @@        let cps = Strings.toList s           len = Lists.length cps-          first = Optionals.fromOptional 0 (Lists.maybeHead cps)-          rest = Logic.ifElse (Equality.gt len 0) (Lists.drop 1 cps) []-      in (Logic.and (Equality.gt len 1) (Logic.and (Equality.equal first 84) (allDigits rest)))+          first = Optionals.withDefault 0 (Lists.head cps)+          rest = Logic.ifElse (Ordering.gt len 0) (Lists.drop 1 cps) []+      in (Logic.and (Ordering.gt len 1) (Logic.and (Equality.equal first 84) (allDigits rest)))  -- | Convert a labeled statement to an AST expression labeledStatementToExpr :: Syntax.LabeledStatement -> Ast.Expr@@ -625,7 +626,7 @@       Syntax.LiteralBoolean v0 -> Serialization.cst (Logic.ifElse v0 "true" "false")       Syntax.LiteralNull -> Serialization.cst "null"       Syntax.LiteralUndefined -> Serialization.cst "undefined"-      Syntax.LiteralBigInt v0 -> Serialization.cst (Strings.cat2 (Literals.showBigint v0) "n")+      Syntax.LiteralBigInt v0 -> Serialization.cst (Strings.concat2 (Literals.showBigint v0) "n")       Syntax.LiteralTemplate v0 -> templateLiteralToExpr v0  -- | Convert a member expression to an AST expression@@ -763,8 +764,8 @@ patternToString pat =     case pat of       Syntax.PatternIdentifier v0 -> Syntax.unIdentifier v0-      Syntax.PatternRest v0 -> Strings.cat2 "..." (patternToString (Syntax.unRestElement v0))-      Syntax.PatternTyped v0 -> Strings.cat [+      Syntax.PatternRest v0 -> Strings.concat2 "..." (patternToString (Syntax.unRestElement v0))+      Syntax.PatternTyped v0 -> Strings.concat [         patternToString (Syntax.typedPatternPattern v0),         ": ",         (tsTypeExpressionToString (Syntax.typedPatternType v0))]@@ -834,7 +835,7 @@           singleQuote = Syntax.stringLiteralSingleQuote s           quote = Logic.ifElse singleQuote "'" "\""           escaped = escapeString value singleQuote-      in (Serialization.cst (Strings.cat [+      in (Serialization.cst (Strings.concat [         quote,         escaped,         quote]))@@ -869,9 +870,9 @@        let quasis = Syntax.templateLiteralQuasis t           exprs = Syntax.templateLiteralExpressions t-      in (Serialization.cst (Strings.cat [+      in (Serialization.cst (Strings.concat [         "`",-        (Strings.intercalate "" (Lists.map (\q -> Syntax.templateElementValue q) quasis)),+        (Strings.join "" (Lists.map (\q -> Syntax.templateElementValue q) quasis)),         "`"]))  -- | Convert a throw statement to an AST expression@@ -884,20 +885,20 @@ -- | Convert a string to a TypeScript line comment. Empty source lines emit `//` (no trailing space). toLineComment :: String -> String toLineComment s =-    Strings.intercalate "\n" (Lists.map (\line -> Logic.ifElse (Equality.equal line "") "//" (Strings.cat2 "// " line)) (Strings.lines s))+    Strings.join "\n" (Lists.map (\line -> Logic.ifElse (Equality.equal line "") "//" (Strings.concat2 "// " line)) (Strings.lines s))  -- | Format a description and tags as a JSDoc comment. Empty doc lines emit ` *` (no trailing space) so blank lines don't carry trailing whitespace. toTypeScriptComments :: String -> [Syntax.DocumentationTag] -> String toTypeScriptComments desc tags =        let descLines =-              Logic.ifElse (Equality.equal desc "") [] (Lists.map (\line -> Logic.ifElse (Equality.equal line "") " *" (Strings.cat2 " * " line)) (Strings.lines desc))+              Logic.ifElse (Equality.equal desc "") [] (Lists.map (\line -> Logic.ifElse (Equality.equal line "") " *" (Strings.concat2 " * " line)) (Strings.lines desc))           tagLines = Lists.map documentationTagToLine tags           allLines =                   Lists.concat [                     descLines,                     tagLines]-      in (Logic.ifElse (Lists.null allLines) "" (Strings.intercalate "\n" (Lists.concat [+      in (Logic.ifElse (Lists.null allLines) "" (Strings.join "\n" (Lists.concat [         [           "/**"],         allLines,@@ -938,25 +939,25 @@       Syntax.TypeExpressionAny -> "any"       Syntax.TypeExpressionVoid -> "void"       Syntax.TypeExpressionNever -> "never"-      Syntax.TypeExpressionArray v0 -> Strings.cat [+      Syntax.TypeExpressionArray v0 -> Strings.concat [         "ReadonlyArray<",         (tsTypeExpressionToString (Syntax.unArrayTypeExpression v0)),         ">"]-      Syntax.TypeExpressionTuple v0 -> Strings.cat [+      Syntax.TypeExpressionTuple v0 -> Strings.concat [         "readonly [",-        (Strings.intercalate ", " (Lists.map tsTypeExpressionToString v0)),+        (Strings.join ", " (Lists.map tsTypeExpressionToString v0)),         "]"]-      Syntax.TypeExpressionUnion v0 -> Strings.intercalate " | " (Lists.map tsTypeExpressionToString v0)-      Syntax.TypeExpressionIntersection v0 -> Strings.intercalate " & " (Lists.map tsTypeExpressionToString v0)-      Syntax.TypeExpressionParameterized v0 -> Strings.cat [+      Syntax.TypeExpressionUnion v0 -> Strings.join " | " (Lists.map tsTypeExpressionToString v0)+      Syntax.TypeExpressionIntersection v0 -> Strings.join " & " (Lists.map tsTypeExpressionToString v0)+      Syntax.TypeExpressionParameterized v0 -> Strings.concat [         tsTypeExpressionToString (Syntax.parameterizedTypeExpressionBase v0),         "<",-        (Strings.intercalate ", " (Lists.map tsTypeExpressionToString (Syntax.parameterizedTypeExpressionArguments v0))),+        (Strings.join ", " (Lists.map tsTypeExpressionToString (Syntax.parameterizedTypeExpressionArguments v0))),         ">"]-      Syntax.TypeExpressionOptional v0 -> Strings.cat [+      Syntax.TypeExpressionOptional v0 -> Strings.concat [         tsTypeExpressionToString v0,         " | undefined"]-      Syntax.TypeExpressionReadonly v0 -> Strings.cat2 "readonly " (tsTypeExpressionToString v0)+      Syntax.TypeExpressionReadonly v0 -> Strings.concat2 "readonly " (tsTypeExpressionToString v0)       Syntax.TypeExpressionUnknown -> "unknown"       Syntax.TypeExpressionFunction _ -> "((...args: any[]) => any)"       _ -> "unknown"@@ -970,7 +971,7 @@       Syntax.TypeExpressionVoid -> "void"       Syntax.TypeExpressionNever -> "never"       Syntax.TypeExpressionLiteral _ -> "literal"-      Syntax.TypeExpressionArray v0 -> Strings.cat2 (typeExpressionToString (Syntax.unArrayTypeExpression v0)) "[]"+      Syntax.TypeExpressionArray v0 -> Strings.concat2 (typeExpressionToString (Syntax.unArrayTypeExpression v0)) "[]"       Syntax.TypeExpressionFunction v0 ->         let params = Syntax.functionTypeExpressionParameters v0             rt = Syntax.functionTypeExpressionReturnType v0@@ -979,28 +980,28 @@                       let i = Pairs.first acc                           soFar = Pairs.second acc                           this =-                                  Strings.cat [+                                  Strings.concat [                                     "_a",                                     (Literals.showInt32 i),                                     ": ",                                     (typeExpressionToString p)]                       in (Math.add i 1, (Lists.concat2 soFar (Lists.pure this)))) (0, []) params)-        in (Strings.cat [+        in (Strings.concat [           "(",-          (Strings.intercalate ", " rendered),+          (Strings.join ", " rendered),           ") => ",           (typeExpressionToString rt)])       Syntax.TypeExpressionObject _ -> "Object"-      Syntax.TypeExpressionUnion v0 -> Strings.intercalate "|" (Lists.map typeExpressionToString v0)+      Syntax.TypeExpressionUnion v0 -> Strings.join "|" (Lists.map typeExpressionToString v0)       Syntax.TypeExpressionParameterized v0 ->         let base = Syntax.parameterizedTypeExpressionBase v0             args = Syntax.parameterizedTypeExpressionArguments v0-        in (Strings.cat [+        in (Strings.concat [           typeExpressionToString base,           "<",-          (Strings.intercalate ", " (Lists.map typeExpressionToString args)),+          (Strings.join ", " (Lists.map typeExpressionToString args)),           ">"])-      Syntax.TypeExpressionOptional v0 -> Strings.cat2 "?" (typeExpressionToString v0)+      Syntax.TypeExpressionOptional v0 -> Strings.concat2 "?" (typeExpressionToString v0)  -- | Render `<pattern>: <type>` (TypeScript parameter / variable type annotation) typedPatternToExpr :: Syntax.TypedPattern -> Ast.Expr@@ -1010,7 +1011,7 @@           typ = Syntax.typedPatternType tp           innerStr = patternToString innerPat           typeStr = tsTypeExpressionToString typ-      in (Serialization.cst (Strings.cat [+      in (Serialization.cst (Strings.concat [         innerStr,         ": ",         typeStr]))