From efc25fcb1ee262e31bd43d7570c7ac8f9504218d Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Tue, 23 Oct 2018 19:18:37 +0200 Subject: [PATCH] Add support for inlining annotations. Currently off by default. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This means that if a type is annotated wiht @genType, and used another type in its definition, the other type will also be considered as annotated. This is currently supported within one file, and not across files. In config. Off by default at the moment. See “Type Expansion” in https://github.com/cristianoc/genType/issues/70 --- src/EmitJs.re | 109 ++++++++++++++++++++++++++++++++++++++----- src/GenTypeCommon.re | 2 + src/Paths.re | 1 + 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/src/EmitJs.re b/src/EmitJs.re index 50590ab4a..6de91d6a0 100644 --- a/src/EmitJs.re +++ b/src/EmitJs.re @@ -757,6 +757,97 @@ let emitImportTypes = (env, emitters), ); +let inlineAnnotatedTypes = + (~config, ~typeDeclarations, typeMap: Translation.typeMap) => { + let visited = ref(StringSet.empty); + let markedAsGenType = ref(StringSet.empty); + let initialAnnotatedTypes = + typeMap + |> StringMap.bindings + |> List.filter(((_, (_, _, genTypeKind, _))) => genTypeKind == GenType); + let inlineTyp = ((_typeName, (_, typ, genTypeKind, _))) => { + let rec visit = typ => + switch (typ) { + | Ident(typeName, _) => + if (visited^ |> StringSet.mem(typeName)) { + (); + } else { + visited := visited^ |> StringSet.add(typeName); + switch (typeMap |> StringMap.find(typeName)) { + | (_, _, GenType | GenTypeOpaque | Generated, _) => () + | (_, typ1, NoGenType, _) => + markedAsGenType := markedAsGenType^ |> StringSet.add(typeName); + logItem("Marking type %s as GenType\n", typeName); + typ1 |> visit; + | exception Not_found => () + }; + } + | Array(t, _) => t |> visit + | Enum(_) => () + | Function({argTypes, retType}) => + argTypes |> List.iter(visit); + retType |> visit; + | GroupOfLabeledArgs(fields) + | Object(fields) + | Record(fields) => fields |> List.iter(({typ}) => typ |> visit) + | Option(t) + | Nullable(t) => t |> visit + | Tuple(innerTypes) => innerTypes |> List.iter(visit) + | TypeVar(_) => () + }; + switch (genTypeKind) { + | GenType => typ |> visit + | Generated + | GenTypeOpaque + | NoGenType => () + }; + }; + if (config.inlineAnnotations) { + initialAnnotatedTypes |> List.iter(inlineTyp); + }; + let newTypeMap = + typeMap + |> StringMap.mapi((typeName, (args, typ, genTypeKind, importTypes)) => + ( + args, + typ, + markedAsGenType^ |> StringSet.mem(typeName) ? + GenType : genTypeKind, + importTypes, + ) + ); + + let annotatedTypeDeclarations = + typeDeclarations + |> List.map(typeDeclaration => + switch ( + typeDeclaration.Translation.exportFromTypeDeclaration.exportKind + ) { + | ExportType(exportType) => + if (markedAsGenType^ |> StringSet.mem(exportType.resolvedTypeName)) { + { + ...typeDeclaration, + exportFromTypeDeclaration: { + ...typeDeclaration.exportFromTypeDeclaration, + genTypeKind: GenType, + }, + }; + } else { + typeDeclaration; + } + | _ => typeDeclaration + } + ) + |> List.filter( + ( + {exportFromTypeDeclaration: {genTypeKind}}: Translation.typeDeclaration, + ) => + genTypeKind != NoGenType + ); + + (newTypeMap, annotatedTypeDeclarations); +}; + let emitTranslationAsString = ( ~config, @@ -773,28 +864,24 @@ let emitTranslationAsString = cmtExportTypeMapCache: StringMap.empty, typesFromOtherFiles: StringMap.empty, }; - let exportTypeMap = - translation.typeDeclarations |> createExportTypeMap(~language); let enumTables = Hashtbl.create(1); - - let typeDeclarationsAnnotated = + let (exportTypeMap, annotatedTypeDeclarations) = translation.typeDeclarations - |> List.filter( - ( - {exportFromTypeDeclaration: {genTypeKind}}: Translation.typeDeclaration, - ) => - genTypeKind != NoGenType + |> createExportTypeMap(~language) + |> inlineAnnotatedTypes( + ~config, + ~typeDeclarations=translation.typeDeclarations, ); let importTypesFromTypeDeclarations = - typeDeclarationsAnnotated + annotatedTypeDeclarations |> List.map((typeDeclaration: Translation.typeDeclaration) => typeDeclaration.importTypes ) |> List.concat; let exportFromTypeDeclarations = - typeDeclarationsAnnotated + annotatedTypeDeclarations |> List.map((typeDeclaration: Translation.typeDeclaration) => typeDeclaration.exportFromTypeDeclaration ); diff --git a/src/GenTypeCommon.re b/src/GenTypeCommon.re index dedb06ff5..022d6e14b 100644 --- a/src/GenTypeCommon.re +++ b/src/GenTypeCommon.re @@ -23,6 +23,7 @@ type config = { bsBlockPath: string, bsCurryPath: string, importPath, + inlineAnnotations: bool, language, module_, modulesMap: ModuleNameMap.t(ModuleName.t), @@ -33,6 +34,7 @@ let defaultConfig = { bsBlockPath: "bs-platform/lib/js/block.js", bsCurryPath: "bs-platform/lib/js/curry.js", importPath: Relative, + inlineAnnotations: false, language: Flow, module_: ES6, modulesMap: ModuleNameMap.empty, diff --git a/src/Paths.re b/src/Paths.re index 29f4bbc4b..e1fb47fe3 100644 --- a/src/Paths.re +++ b/src/Paths.re @@ -222,6 +222,7 @@ let readConfig = () => { | _ => bsCurryPathString }; { + ...defaultConfig, language, module_, importPath,