Browse Source

[display] expose list of metadata/defines (#11399)

* [display] expose meta list (including user defined ones)

* [display] expose defines list (including user defined ones)

* add user vs compiler filtering

* cleanup
Rudy Ges 1 year ago
parent
commit
844dce53e9

+ 12 - 0
src-prebuild/prebuild.ml

@@ -286,6 +286,18 @@ let parse_meta_usage = function
 	| \"TVariable\" -> TVariable
 	| \"TVariable\" -> TVariable
 	| t -> raise (failwith (\"invalid metadata target \" ^ t))
 	| t -> raise (failwith (\"invalid metadata target \" ^ t))
 
 
+let print_meta_usage = function
+	| TClass -> \"TClass\"
+	| TClassField -> \"TClassField\"
+	| TAbstract -> \"TAbstract\"
+	| TAbstractField -> \"TAbstractField\"
+	| TEnum -> \"TEnum\"
+	| TTypedef -> \"TTypedef\"
+	| TAnyField -> \"TAnyField\"
+	| TExpr -> \"TExpr\"
+	| TTypeParameter -> \"TTypeParameter\"
+	| TVariable -> \"TVariable\"
+
 type meta_parameter =
 type meta_parameter =
 	| HasParam of string
 	| HasParam of string
 	| Platforms of platform list
 	| Platforms of platform list

+ 2 - 2
src/compiler/args.ml

@@ -158,7 +158,7 @@ let parse_args com =
 				let all,max_length = Define.get_user_documentation_list com.user_defines in
 				let all,max_length = Define.get_user_documentation_list com.user_defines in
 				let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
 				let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
 				List.iter (fun msg -> com.print (msg ^ "\n")) all;
 				List.iter (fun msg -> com.print (msg ^ "\n")) all;
-				exit 0
+				raise Abort
 			)
 			)
 		),"","print help for all user defines");
 		),"","print help for all user defines");
 		("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() ->
 		("Miscellaneous",["--help-metas"],[], Arg.Unit (fun() ->
@@ -173,7 +173,7 @@ let parse_args com =
 				let all,max_length = Meta.get_user_documentation_list com.user_metas in
 				let all,max_length = Meta.get_user_documentation_list com.user_metas in
 				let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
 				let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" max_length n (limit_string doc (max_length + 3))) all in
 				List.iter (fun msg -> com.print (msg ^ "\n")) all;
 				List.iter (fun msg -> com.print (msg ^ "\n")) all;
-				exit 0
+				raise Abort
 			)
 			)
 		),"","print help for all user metadatas");
 		),"","print help for all user metadatas");
 	] in
 	] in

+ 2 - 2
src/compiler/displayOutput.ml

@@ -71,8 +71,8 @@ let print_fields fields =
 		| ITPackage(path,_) -> "package",snd path,"",None
 		| ITPackage(path,_) -> "package",snd path,"",None
 		| ITModule path -> "type",snd path,"",None
 		| ITModule path -> "type",snd path,"",None
 		| ITMetadata  meta ->
 		| ITMetadata  meta ->
-			let s,(doc,_),_ = Meta.get_info meta in
-			"metadata","@" ^ s,"",doc_from_string doc
+			let s,data  = Meta.get_info meta in
+			"metadata","@" ^ s,"",doc_from_string data.m_doc
 		| ITTimer(name,value) -> "timer",name,"",doc_from_string value
 		| ITTimer(name,value) -> "timer",name,"",doc_from_string value
 		| ITLiteral s ->
 		| ITLiteral s ->
 			let t = match k.ci_type with None -> t_dynamic | Some (t,_) -> t in
 			let t = match k.ci_type with None -> t_dynamic | Some (t,_) -> t in

+ 65 - 0
src/context/display/displayJson.ml

@@ -156,6 +156,71 @@ let handler =
 			hctx.display#set_display_file (hctx.jsonrpc#get_bool_param "wasAutoTriggered") true;
 			hctx.display#set_display_file (hctx.jsonrpc#get_bool_param "wasAutoTriggered") true;
 			hctx.display#enable_display DMSignature
 			hctx.display#enable_display DMSignature
 		);
 		);
+		"display/metadata", (fun hctx ->
+			let include_compiler_meta = hctx.jsonrpc#get_bool_param "compiler" in
+			let include_user_meta = hctx.jsonrpc#get_bool_param "user" in
+
+			hctx.com.callbacks#add_after_init_macros (fun () ->
+				let all = Meta.get_meta_list hctx.com.user_metas in
+				let all = List.filter (fun (_, (data:Meta.meta_infos)) ->
+					match data.m_origin with
+					| Compiler when include_compiler_meta -> true
+					| UserDefined _ when include_user_meta -> true
+					| _ -> false
+				) all in
+
+				hctx.send_result (jarray (List.map (fun (t, (data:Meta.meta_infos)) ->
+					let fields = [
+						"name", jstring t;
+						"doc", jstring data.m_doc;
+						"parameters", jarray (List.map jstring data.m_params);
+						"platforms", jarray (List.map (fun p -> jstring (platform_name p)) data.m_platforms);
+						"targets", jarray (List.map (fun u -> jstring (Meta.print_meta_usage u)) data.m_used_on);
+						"internal", jbool data.m_internal;
+						"origin", jstring (match data.m_origin with
+							| Compiler -> "haxe compiler"
+							| UserDefined None -> "user-defined"
+							| UserDefined (Some o) -> o
+						);
+						"links", jarray (List.map jstring data.m_links)
+					] in
+
+					(jobject fields)
+				) all))
+			)
+		);
+		"display/defines", (fun hctx ->
+			let include_compiler_defines = hctx.jsonrpc#get_bool_param "compiler" in
+			let include_user_defines = hctx.jsonrpc#get_bool_param "user" in
+
+			hctx.com.callbacks#add_after_init_macros (fun () ->
+				let all = Define.get_define_list hctx.com.user_defines in
+				let all = List.filter (fun (_, (data:Define.define_infos)) ->
+					match data.d_origin with
+					| Compiler when include_compiler_defines -> true
+					| UserDefined _ when include_user_defines -> true
+					| _ -> false
+				) all in
+
+				hctx.send_result (jarray (List.map (fun (t, (data:Define.define_infos)) ->
+					let fields = [
+						"name", jstring t;
+						"doc", jstring data.d_doc;
+						"parameters", jarray (List.map jstring data.d_params);
+						"platforms", jarray (List.map (fun p -> jstring (platform_name p)) data.d_platforms);
+						"origin", jstring (match data.d_origin with
+							| Compiler -> "haxe compiler"
+							| UserDefined None -> "user-defined"
+							| UserDefined (Some o) -> o
+						);
+						"deprecated", jopt jstring data.d_deprecated;
+						"links", jarray (List.map jstring data.d_links)
+					] in
+
+					(jobject fields)
+				) all))
+			)
+		);
 		"server/readClassPaths", (fun hctx ->
 		"server/readClassPaths", (fun hctx ->
 			hctx.com.callbacks#add_after_init_macros (fun () ->
 			hctx.com.callbacks#add_after_init_macros (fun () ->
 				let cc = hctx.display#get_cs#get_context (Define.get_signature hctx.com.defines) in
 				let cc = hctx.display#get_cs#get_context (Define.get_signature hctx.com.defines) in

+ 46 - 15
src/core/define.ml

@@ -19,7 +19,35 @@ type define_origin =
 	| Compiler
 	| Compiler
 	| UserDefined of string option
 	| UserDefined of string option
 
 
-let infos ?user_defines d = match (user_defines,d) with
+type define_infos = {
+	d_doc : string;
+	d_params : string list;
+	d_platforms : Globals.platform list;
+	d_origin : define_origin;
+	d_links : string list;
+	d_deprecated : string option;
+}
+
+let infos ?user_defines d =
+	let extract_infos (t, (doc, flags), origin) =
+		let params = ref [] and pfs = ref [] and links = ref [] and deprecated = ref None in
+		List.iter (function
+			| HasParam s -> params := s :: !params
+			| Platforms fl -> pfs := fl @ !pfs
+			| Link url -> links := url :: !links
+			| Deprecated s -> deprecated := Some s
+		) flags;
+		(t, {
+			d_doc = doc;
+			d_params = !params;
+			d_platforms = !pfs;
+			d_origin = origin;
+			d_links = !links;
+			d_deprecated = !deprecated;
+		})
+	in
+
+	extract_infos (match (user_defines,d) with
 	| (Some(user_defines), Custom(s)) when (Hashtbl.mem user_defines s) ->
 	| (Some(user_defines), Custom(s)) when (Hashtbl.mem user_defines s) ->
 		let infos = Hashtbl.find user_defines s in
 		let infos = Hashtbl.find user_defines s in
 		(s, (infos.doc, infos.flags), (UserDefined infos.source))
 		(s, (infos.doc, infos.flags), (UserDefined infos.source))
@@ -27,30 +55,23 @@ let infos ?user_defines d = match (user_defines,d) with
 		(s, ("", []), Compiler)
 		(s, ("", []), Compiler)
 	| _ ->
 	| _ ->
 		let def,infos = DefineList.infos d in
 		let def,infos = DefineList.infos d in
-		(def, infos, Compiler)
+		(def, infos, Compiler))
 
 
 let get_define_key d =
 let get_define_key d =
-	match (infos d) with (s,_,_) -> s
+	match (infos d) with (s,_) -> s
 
 
 let get_documentation user_defines d =
 let get_documentation user_defines d =
-	let t, (doc,flags), origin = infos ~user_defines:user_defines d in
-	let params = ref [] and pfs = ref [] in
-	List.iter (function
-		| HasParam s -> params := s :: !params
-		| Platforms fl -> pfs := fl @ !pfs
-		| Link _ -> ()
-		| Deprecated _ -> ()
-	) flags;
-	let params = (match List.rev !params with
+	let t, data = infos ~user_defines:user_defines d in
+	let params = (match List.rev data.d_params with
 		| [] -> ""
 		| [] -> ""
 		| l -> "<" ^ String.concat ">, <" l ^ "> "
 		| l -> "<" ^ String.concat ">, <" l ^ "> "
 	) in
 	) in
-	let origin = match origin with
+	let origin = match data.d_origin with
 		| UserDefined Some s -> " (from " ^ s ^ ")"
 		| UserDefined Some s -> " (from " ^ s ^ ")"
 		| Compiler | UserDefined None -> ""
 		| Compiler | UserDefined None -> ""
 	in
 	in
-	let pfs = platform_list_help (List.rev !pfs) in
-	(String.concat "-" (ExtString.String.nsplit t "_")), params ^ doc ^ pfs ^ origin
+	let pfs = platform_list_help (List.rev data.d_platforms) in
+	(String.concat "-" (ExtString.String.nsplit t "_")), params ^ data.d_doc ^ pfs ^ origin
 
 
 let get_documentation_list user_defines =
 let get_documentation_list user_defines =
 	let m = ref 0 in
 	let m = ref 0 in
@@ -77,6 +98,16 @@ let get_user_documentation_list user_defines =
 	let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) user_defines_list in
 	let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) user_defines_list in
 	all,!m
 	all,!m
 
 
+let get_define_list user_defines =
+	let rec loop i acc =
+		let d = Obj.magic i in
+		if d <> Last then (infos ~user_defines d) :: loop (i + 1) acc
+		else acc
+	in
+
+	let all = loop 0 (Hashtbl.fold (fun str _ acc -> (infos ~user_defines (Custom str)) :: acc) user_defines []) in
+	List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) all
+
 let raw_defined ctx k =
 let raw_defined ctx k =
 	PMap.mem k ctx.values
 	PMap.mem k ctx.values
 
 

+ 13 - 34
src/core/display/completionItem.ml

@@ -761,42 +761,21 @@ let to_json ctx index item =
 		]
 		]
 		| ITMetadata meta ->
 		| ITMetadata meta ->
 			let open Meta in
 			let open Meta in
-			let name,(doc,params),origin = Meta.get_info meta in
+			let name,data = Meta.get_info meta in
 			let name = "@" ^ name in
 			let name = "@" ^ name in
-			let usage_to_string = function
-				| TClass -> "TClass"
-				| TClassField -> "TClassField"
-				| TAbstract -> "TAbstract"
-				| TAbstractField -> "TAbstractField"
-				| TEnum -> "TEnum"
-				| TTypedef -> "TTypedef"
-				| TAnyField -> "TAnyField"
-				| TExpr -> "TExpr"
-				| TTypeParameter -> "TTypeParameter"
-				| TVariable -> "TVariable"
-			in
-			let origin = match origin with
-				| Compiler -> Some "haxe compiler"
-				| UserDefined s -> s
-			in
-			let rec loop internal params platforms targets links l = match l with
-				| HasParam s :: l -> loop internal (s :: params) platforms targets links l
-				| Platforms pls :: l -> loop internal params ((List.map platform_name pls) @ platforms) targets links l
-				| UsedOn usages :: l -> loop internal params platforms ((List.map usage_to_string usages) @ targets) links l
-				| UsedInternally :: l -> loop true params platforms targets links l
-				| Link url :: l -> loop internal params platforms targets (url :: links) l
-				| [] -> internal,params,platforms,targets,links
-			in
-			let internal,params,platforms,targets,links = loop false [] [] [] [] params in
 			"Metadata",jobject [
 			"Metadata",jobject [
-				"name",jstring name;
-				"doc",jstring doc;
-				"parameters",jlist jstring params;
-				"platforms",jlist jstring platforms;
-				"targets",jlist jstring targets;
-				"internal",jbool internal;
-				"links",jlist jstring links;
-				"origin",jopt jstring origin;
+				"name", jstring name;
+				"doc", jstring data.m_doc;
+				"parameters", jarray (List.map jstring data.m_params);
+				"platforms", jarray (List.map (fun p -> jstring (platform_name p)) data.m_platforms);
+				"targets", jarray (List.map (fun u -> jstring (Meta.print_meta_usage u)) data.m_used_on);
+				"internal", jbool data.m_internal;
+				"origin", jstring (match data.m_origin with
+					| Compiler -> "haxe compiler"
+					| UserDefined None -> "user-defined"
+					| UserDefined (Some o) -> o
+				);
+				"links", jarray (List.map jstring data.m_links)
 			]
 			]
 		| ITKeyword kwd ->"Keyword",jobject [
 		| ITKeyword kwd ->"Keyword",jobject [
 			"name",jstring (s_keyword kwd)
 			"name",jstring (s_keyword kwd)

+ 2 - 2
src/core/json/genjson.ml

@@ -177,8 +177,8 @@ and generate_metadata_entry ctx (m,el,p) =
 
 
 and generate_metadata ctx ml =
 and generate_metadata ctx ml =
 	let ml = List.filter (fun (m,_,_) ->
 	let ml = List.filter (fun (m,_,_) ->
-		let (_,(_,flags),_) = Meta.get_info m in
-		not (List.mem UsedInternally flags)
+		let (_,data) = Meta.get_info m in
+		not data.m_internal
 	) ml in
 	) ml in
 	jlist (generate_metadata_entry ctx) ml
 	jlist (generate_metadata_entry ctx) ml
 
 

+ 52 - 22
src/core/meta.ml

@@ -20,18 +20,49 @@ type meta_origin =
 	| Compiler
 	| Compiler
 	| UserDefined of string option
 	| UserDefined of string option
 
 
+type meta_infos = {
+	m_internal : bool;
+	m_doc : string;
+	m_params : string list;
+	m_platforms : Globals.platform list;
+	m_used_on : meta_usage list;
+	m_origin : meta_origin;
+	m_links : string list;
+}
+
 let register_user_meta user_metas s data =
 let register_user_meta user_metas s data =
 	Hashtbl.replace user_metas s data
 	Hashtbl.replace user_metas s data
 
 
-let get_info ?user_metas m = match (user_metas,m) with
+let get_info ?user_metas m =
+	let extract_infos (t, (doc, flags), origin) =
+			let params = ref [] and used = ref [] and pfs = ref [] and links = ref [] and internal = ref false in
+			List.iter (function
+				| HasParam s -> params := s :: !params
+				| Platforms fl -> pfs := fl @ !pfs
+				| UsedOn ul -> used := ul @ !used
+				| UsedInternally -> internal := true
+				| Link url -> links := url :: !links
+			) flags;
+			(t,{
+				m_internal = !internal;
+				m_doc = doc;
+				m_params = !params;
+				m_platforms = !pfs;
+				m_used_on = !used;
+				m_origin = origin;
+				m_links = !links;
+			})
+	in
+
+	extract_infos (match (user_metas,m) with
 	| (Some(user_metas), Custom(s)) when (Hashtbl.mem user_metas s) ->
 	| (Some(user_metas), Custom(s)) when (Hashtbl.mem user_metas s) ->
 		let infos = Hashtbl.find user_metas s in
 		let infos = Hashtbl.find user_metas s in
 		(s, (infos.doc, infos.flags), (UserDefined infos.source))
 		(s, (infos.doc, infos.flags), (UserDefined infos.source))
 	| _ ->
 	| _ ->
 		let meta,infos = MetaList.get_info m in
 		let meta,infos = MetaList.get_info m in
-		(meta, infos, Compiler)
+		(meta, infos, Compiler))
 
 
-let to_string m = match (get_info m) with (s,_,_) -> s
+let to_string m = match (get_info m) with (s,_) -> s
 
 
 let hmeta =
 let hmeta =
 	let h = Hashtbl.create 0 in
 	let h = Hashtbl.create 0 in
@@ -53,30 +84,19 @@ let from_string s =
 	| '$' -> Dollar (String.sub s 1 (String.length s - 1))
 	| '$' -> Dollar (String.sub s 1 (String.length s - 1))
 	| _ -> Custom s
 	| _ -> Custom s
 
 
-let get_documentation user_metas d =
-	let t, (doc,flags), origin = get_info ~user_metas:user_metas d in
-	if not (List.mem UsedInternally flags) then begin
-		let params = ref [] and used = ref [] and pfs = ref [] in
-		List.iter (function
-			| HasParam s -> params := s :: !params
-			| Platforms fl -> pfs := fl @ !pfs
-			| UsedOn ul -> used := ul @ !used
-			| UsedInternally -> die "" __LOC__
-			| Link _ -> ()
-		) flags;
-		let params = (match List.rev !params with
+let get_documentation user_metas m =
+	let t, data = get_info ~user_metas:user_metas m in
+	if data.m_internal then None else
+		let params = (match List.rev data.m_params with
 			| [] -> ""
 			| [] -> ""
 			| l -> "(<" ^ String.concat ">, <" l ^ ">) "
 			| l -> "(<" ^ String.concat ">, <" l ^ ">) "
 		) in
 		) in
-		let pfs = platform_list_help (List.rev !pfs) in
-		let origin = match origin with
+		let pfs = platform_list_help (List.rev data.m_platforms) in
+		let origin = match data.m_origin with
 			| UserDefined Some s -> " (from " ^ s ^ ")"
 			| UserDefined Some s -> " (from " ^ s ^ ")"
 			| Compiler | UserDefined None -> ""
 			| Compiler | UserDefined None -> ""
 		in
 		in
-		let str = "@" ^ t in
-		Some (str,params ^ doc ^ pfs ^ origin)
-	end else
-		None
+		Some ("@" ^ t, params ^ data.m_doc ^ pfs ^ origin)
 
 
 let get_documentation_list user_metas =
 let get_documentation_list user_metas =
 	let m = ref 0 in
 	let m = ref 0 in
@@ -93,6 +113,16 @@ let get_documentation_list user_metas =
 	let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
 	let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
 	all,!m
 	all,!m
 
 
+let get_meta_list user_metas =
+	let rec loop i acc =
+		let d = Obj.magic i in
+		if d <> Last then (get_info ~user_metas d) :: loop (i + 1) acc
+		else acc
+	in
+
+	let all = loop 0 (Hashtbl.fold (fun str _ acc -> (get_info ~user_metas (Custom str)) :: acc) user_metas []) in
+	List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) all
+
 let get_all user_metas =
 let get_all user_metas =
 	let rec loop i acc =
 	let rec loop i acc =
 		let d = Obj.magic i in
 		let d = Obj.magic i in
@@ -108,7 +138,7 @@ let get_user_documentation_list user_metas =
 	let user_meta_list = (Hashtbl.fold (fun meta _ acc ->
 	let user_meta_list = (Hashtbl.fold (fun meta _ acc ->
 		begin match get_documentation user_metas (Custom meta) with
 		begin match get_documentation user_metas (Custom meta) with
 			| None -> acc
 			| None -> acc
-			| Some (str, desc) ->
+			| Some (str,desc) ->
 				if String.length str > !m then m := String.length str;
 				if String.length str > !m then m := String.length str;
 				(str,desc) :: acc
 				(str,desc) :: acc
 		end
 		end

+ 26 - 0
std/haxe/display/Display.hx

@@ -78,6 +78,16 @@ class DisplayMethods {
 	**/
 	**/
 	static inline var SignatureHelp = new HaxeRequestMethod<SignatureHelpParams, SignatureHelpResult>("display/signatureHelp");
 	static inline var SignatureHelp = new HaxeRequestMethod<SignatureHelpParams, SignatureHelpResult>("display/signatureHelp");
 
 
+	/**
+		The metadata request is sent from the client to Haxe to get a list of all registered metadata and their documentation.
+	**/
+	static inline var Metadata = new HaxeRequestMethod<MetadataParams, MetadataResult>("display/metadata");
+
+	/**
+		The defines request is sent from the client to Haxe to get a list of all registered defines and their documentation.
+	**/
+	static inline var Defines = new HaxeRequestMethod<DefinesParams, DefinesResult>("display/defines");
+
 	/*
 	/*
 		TODO:
 		TODO:
 
 
@@ -306,6 +316,8 @@ typedef Define = {
 	var parameters:Array<String>;
 	var parameters:Array<String>;
 	var platforms:Array<Platform>;
 	var platforms:Array<Platform>;
 	var links:Array<String>;
 	var links:Array<String>;
+	var ?origin:String;
+	var ?deprecated:String;
 }
 }
 
 
 typedef Keyword = {
 typedef Keyword = {
@@ -543,6 +555,20 @@ typedef SignatureItem = {
 
 
 typedef SignatureHelpResult = Response<Null<SignatureItem>>;
 typedef SignatureHelpResult = Response<Null<SignatureItem>>;
 
 
+typedef MetadataParams = {
+	var compiler:Bool;
+	var user:Bool;
+}
+
+typedef MetadataResult = Response<Array<Metadata>>;
+
+typedef DefinesParams = {
+	var compiler:Bool;
+	var user:Bool;
+}
+
+typedef DefinesResult = Response<Array<Define>>;
+
 /** General types **/
 /** General types **/
 typedef PositionParams = FileParams & {
 typedef PositionParams = FileParams & {
 	/** Unicode character offset in the file. **/
 	/** Unicode character offset in the file. **/

+ 105 - 0
tests/server/src/cases/ServerTests.hx

@@ -3,6 +3,7 @@ package cases;
 import haxe.display.Display;
 import haxe.display.Display;
 import haxe.display.FsPath;
 import haxe.display.FsPath;
 import haxe.display.Server;
 import haxe.display.Server;
+import haxe.io.Path;
 import utest.Assert;
 import utest.Assert;
 
 
 using StringTools;
 using StringTools;
@@ -235,6 +236,110 @@ class ServerTests extends TestCase {
 		utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao
 		utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao
 	}
 	}
 
 
+	function testMetadata() {
+		var dummy_path = Path.join(["..", "misc", "projects", "Issue10844"]);
+		Sys.command("haxelib", ["dev", "dummy_doc_dep", Path.join([dummy_path, "dummy_doc_dep"])]);
+		Sys.command("haxelib", ["dev", "dummy_doc", Path.join([dummy_path, "dummy_doc"])]);
+		var args = ["-lib", "dummy_doc"];
+
+		runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: true, user: true}, function(meta) {
+			var analyzer = Lambda.find(meta, m -> m.name == ':analyzer');
+			Assert.notNull(analyzer);
+			Assert.equals("Used to configure the static analyzer.", analyzer.doc);
+			Assert.equals("haxe compiler", analyzer.origin);
+
+			var dummy_doc = Lambda.find(meta, m -> m.name == ':foo');
+			Assert.notNull(dummy_doc);
+			Assert.equals("Some documentation for the @:foo metadata for cpp platform", dummy_doc.doc);
+			Assert.equals("dummy_doc", dummy_doc.origin);
+			Assert.equals(Platform.Cpp, dummy_doc.platforms[0]);
+
+			var dummy_doc = Lambda.find(meta, m -> m.name == ':bar');
+			Assert.notNull(dummy_doc);
+			Assert.equals("dummy_doc", dummy_doc.origin);
+			Assert.equals(MetadataTarget.Class, dummy_doc.targets[0]);
+
+			var dummy_doc_dep = Lambda.find(meta, m -> m.name == ':baz');
+			Assert.notNull(dummy_doc_dep);
+			Assert.equals("dummy_doc_dep", dummy_doc_dep.origin);
+		});
+
+		runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: true, user: false}, function(meta) {
+			var analyzer = Lambda.find(meta, m -> m.name == ':analyzer');
+			Assert.notNull(analyzer);
+
+			var dummy_doc = Lambda.find(meta, m -> m.name == ':foo');
+			Assert.isNull(dummy_doc);
+
+			var dummy_doc_dep = Lambda.find(meta, m -> m.name == ':baz');
+			Assert.isNull(dummy_doc_dep);
+		});
+
+		runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: false, user: true}, function(meta) {
+			var analyzer = Lambda.find(meta, m -> m.name == ':analyzer');
+			Assert.isNull(analyzer);
+
+			var dummy_doc = Lambda.find(meta, m -> m.name == ':foo');
+			Assert.notNull(dummy_doc);
+
+			var dummy_doc_dep = Lambda.find(meta, m -> m.name == ':baz');
+			Assert.notNull(dummy_doc_dep);
+		});
+
+		runHaxeJsonCb(args, DisplayMethods.Metadata, {compiler: false, user: false}, function(meta) {
+			Assert.equals(0, meta.length);
+		});
+	}
+
+	function testDefines() {
+		var dummy_path = Path.join(["..", "misc", "projects", "Issue10844"]);
+		Sys.command("haxelib", ["dev", "dummy_doc_dep", Path.join([dummy_path, "dummy_doc_dep"])]);
+		Sys.command("haxelib", ["dev", "dummy_doc", Path.join([dummy_path, "dummy_doc"])]);
+		var args = ["-lib", "dummy_doc"];
+
+		runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: true, user: true}, function(defines) {
+			var debug = Lambda.find(defines, d -> d.name == 'debug');
+			Assert.notNull(debug);
+			Assert.equals("Activated when compiling with -debug.", debug.doc);
+			Assert.equals("haxe compiler", debug.origin);
+
+			var dummy_doc = Lambda.find(defines, d -> d.name == 'no-bullshit');
+			Assert.notNull(dummy_doc);
+			Assert.equals("Only very important stuff should be compiled", dummy_doc.doc);
+			Assert.equals("dummy_doc", dummy_doc.origin);
+
+			var dummy_doc_dep = Lambda.find(defines, d -> d.name == 'dummy');
+			Assert.notNull(dummy_doc_dep);
+			Assert.equals("dummy_doc_dep", dummy_doc_dep.origin);
+		});
+
+		runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: true, user: false}, function(defines) {
+			var debug = Lambda.find(defines, d -> d.name == 'debug');
+			Assert.notNull(debug);
+
+			var dummy_doc = Lambda.find(defines, d -> d.name == 'no-bullshit');
+			Assert.isNull(dummy_doc);
+
+			var dummy_doc_dep = Lambda.find(defines, d -> d.name == 'dummy');
+			Assert.isNull(dummy_doc_dep);
+		});
+
+		runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: false, user: true}, function(defines) {
+			var debug = Lambda.find(defines, d -> d.name == 'debug');
+			Assert.isNull(debug);
+
+			var dummy_doc = Lambda.find(defines, d -> d.name == 'no-bullshit');
+			Assert.notNull(dummy_doc);
+
+			var dummy_doc_dep = Lambda.find(defines, d -> d.name == 'dummy');
+			Assert.notNull(dummy_doc_dep);
+		});
+
+		runHaxeJsonCb(args, DisplayMethods.Defines, {compiler: false, user: false}, function(defines) {
+			Assert.equals(0, defines.length);
+		});
+	}
+
 	function test10986() {
 	function test10986() {
 		vfs.putContent("Main.hx", getTemplate("issues/Issue10986/Main.hx"));
 		vfs.putContent("Main.hx", getTemplate("issues/Issue10986/Main.hx"));
 		vfs.putContent("haxe/ds/Vector.hx", getTemplate("issues/Issue10986/Vector.hx"));
 		vfs.putContent("haxe/ds/Vector.hx", getTemplate("issues/Issue10986/Vector.hx"));