@@ -12,7 +12,11 @@ using haxe.macro.ComplexTypeTools;
1212using Lambda ;
1313using StringTools ;
1414
15- typedef Either <T , V > = Dynamic ;
15+ enum abstract WrapMode (String ) from String to String
16+ {
17+ var Blacklist ;
18+ var Whitelist ;
19+ }
1620
1721typedef WrapperParams =
1822{
@@ -22,37 +26,40 @@ typedef WrapperParams =
2226 var classes : Array <String >;
2327
2428 /**
25- * Aliases to functions, for instance `{ "getAnonymousField": ["field"]] }` generates a `field` function that calls `getAnonymousField`.
29+ * Aliases to functions, for instance `{ "getAnonymousField": ["field"] }` generates a `field` function that calls `getAnonymousField`.
2630 * It works in both ways, so you can generate aliases in the class that point to the ones in `classes` and vice-versa.
27- * This should be strictly structured as { fieldName: Array<String> }, failure to comply will result in undefined behaviour.
31+ * This should be strictly structured as ` { fieldName: Array<String> }` , failure to comply will result in undefined behaviour.
2832 */
2933 var ? aliases : {};
3034
3135 /**
32- * Functions that should be wrapped based on `whitelistMode `.
36+ * Functions that should be wrapped based on `wrapMode `.
3337 * If a function is part of an alias or the ignore list, this will have no effect on it.
3438 */
35- var ? fieldList : Array <String >;
39+ var ? customWrapList : Array <String >;
3640
3741 /**
38- * Defines how fields in `fieldList` are wrapped.
39- * By default it's `true`, which means fields outside the list are blacklisted by default.
42+ * Defines how fields in `customWrapList` are wrapped.
43+ * If it's `Whitelist` fields outside the list are blacklisted by default.
44+ *
45+ * @default `Whitelist`
4046 */
41- var ? whitelistMode : Bool ;
47+ var ? customWrapMode : WrapMode ;
4248
4349 /**
44- * Functions in the provided classes that the macro should skip generating .
50+ * Functions in ` classes` that the macro should not generate .
4551 * If a function is part of an alias, this will have no effect on it.
4652 */
4753 var ? ignoreList : Array <String >;
4854}
4955
5056/**
5157 * Generates fields that wrap functions from the provided classes in a way that
52- * they'll throw an error if accessed or call the original function if whitelisted.
58+ * they'll throw an error if accessed, or call the original function if whitelisted.
5359 * It is best to be used with classes with only static fields.
5460 *
5561 * You can add your own sandboxed implementations of the fields and make aliases to them (see `BlacklistParams.aliases`).
62+ * Note that if the field already exists in `BlacklistParams.classes` you should add `@:blacklistOverride` to it.
5663 */
5764class BlacklistClassMacro
5865{
@@ -61,69 +68,45 @@ class BlacklistClassMacro
6168 */
6269 static final BLACKLISTED_FUNCTION_DOC : String = " This function is not allowed to be used by scripts.\n @throws error When called by a script." ;
6370
64- static function build (params : WrapperParams ): Array <Field >
71+ static var buildFields : Array <Field >;
72+ static var processedFieldNames : Array <String > = [];
73+
74+ static inline function containsField (fieldName : String ): Bool
6575 {
66- params . whitelistMode ?? = true ;
67- params . fieldList ?? = [];
76+ return buildFields . exists ( f -> f . name == fieldName ) ;
77+ }
6878
79+ static inline function getField (fieldName : String ): Null <Field >
80+ {
81+ return buildFields .find (f -> f .name == fieldName );
82+ }
83+
84+ static function build (params : WrapperParams ): Array <Field >
85+ {
6986 final classes : Array <ClassType > = [for (c in params .classes ) MacroUtil .getClassType (c )];
7087 if (classes .length == 0 ) Context .fatalError (' Invalid class amount, no classes were provided.' , Context .currentPos ());
7188
72- final buildFields : Array < Field > = Context .getBuildFields ();
73- final generatedFields : Array <Field > = [];
89+ buildFields = Context .getBuildFields ();
90+ var generatedFields : Array <Field > = [];
7491
75- // For convenience...
76- inline function containsField (fieldName : String ): Bool
77- {
78- return buildFields .exists (f -> f .name == fieldName );
79- }
80- inline function getField (fieldName : String ): Null <Field >
81- {
82- return buildFields .find (f -> f .name == fieldName );
83- }
92+ params .customWrapList ?? = [];
93+ params .customWrapMode ?? = Whitelist ;
8494
8595 // NOTE: As much as I wish these could be a map seems like Haxe is unable to parse them as part of the metadata.
8696 final aliases : DynamicAccess <Array <String >> = cast params .aliases ;
87- final fieldsToSkip : Array <String > = params .ignoreList ?. copy () ?? [];
88- final pendingFieldsToWrap : Array <String > = [];
97+ var fieldsToSkip : Array <String > = params .ignoreList ?. copy () ?? [];
98+ var pendingFieldsToWrap : Array <String > = [];
99+
89100 if (aliases != null )
90101 {
91- for (field => aliasFields in aliases )
92- {
93- if (aliasFields .length == 0 ) Context .warning (' No alias fields specified to be generated for " $field "' , Context .currentPos ());
94-
95- final wrappedField : Null <Field > = getField (field );
96- if (wrappedField == null )
97- {
98- // Field might be on the provided classes, put it on queue.
99- pendingFieldsToWrap .push (field );
100- continue ;
101- }
102-
103- for (aliasName in aliasFields )
104- {
105- if (containsField (aliasName ))
106- {
107- Context .error (' Tried to generate " ${aliasName }" alias but it already exists in the class.' , getField (aliasName ).pos );
108- }
109-
110- final wrapper : Null <Field > = generateWrapperField (aliasName , wrappedField );
111- if (wrapper != null )
112- {
113- generatedFields .push (wrapper );
114- fieldsToSkip .push (aliasName );
115- }
116- else
117- Context .error (' Could not generate alias for field " $field "; it may not be a function.' , wrappedField .pos );
118- }
119- }
102+ generatedFields = generateAliases (aliases , pendingFieldsToWrap );
120103 }
121104
122105 for (c in classes )
123106 {
124107 for (field in c .statics .get ())
125108 {
126- if (! field .isPublic || fieldsToSkip .contains (field .name )) continue ;
109+ if (! field .isPublic || fieldsToSkip .contains (field .name ) || ~/ ^ (get | set)_ / . match ( field . name ) ) continue ;
127110
128111 if (containsField (field .name ))
129112 {
@@ -136,8 +119,7 @@ class BlacklistClassMacro
136119 }
137120 continue ;
138121 }
139-
140- final blacklisted : Bool = params .whitelistMode != params .fieldList .contains (field .name );
122+ final blacklisted : Bool = (params .customWrapMode == Whitelist ) != params .customWrapList .contains (field .name );
141123 final wrapper : Null <Field > = generateWrapperField (field .name , field , c .name , blacklisted );
142124 generatedFields .push (wrapper );
143125
@@ -161,12 +143,49 @@ class BlacklistClassMacro
161143 return buildFields .concat (generatedFields );
162144 }
163145
164- static function generateWrapperField (fieldName : String , wrappedField : Either <Field , ClassField >, ? className : String , blacklist : Bool = false ): Null <Field >
146+ static function generateAliases (aliases : DynamicAccess <Array <String >>, ? unresolvedAliases : Array <String >): Array <Field >
147+ {
148+ var result : Array <Field > = [];
149+
150+ for (field => aliasFields in aliases )
151+ {
152+ if (aliasFields .length == 0 ) Context .warning (' No alias fields specified to be generated for " $field "' , Context .currentPos ());
153+
154+ final wrappedField : Null <Field > = getField (field );
155+ if (wrappedField == null )
156+ {
157+ // Field might be on the provided classes, put it on queue.
158+ unresolvedAliases .push (field );
159+ continue ;
160+ }
161+
162+ for (aliasName in aliasFields )
163+ {
164+ if (containsField (aliasName ))
165+ {
166+ Context .error (' Tried to generate " ${aliasName }" alias but it already exists in the class.' , getField (aliasName ).pos );
167+ }
168+
169+ final wrapper : Null <Field > = generateWrapperField (aliasName , wrappedField );
170+ if (wrapper != null )
171+ {
172+ result .push (wrapper );
173+ processedFieldNames .push (aliasName );
174+ }
175+ else
176+ Context .error (' Could not generate alias for field " $field "; it may not be a function.' , wrappedField .pos );
177+ }
178+ }
179+
180+ return result ;
181+ }
182+
183+ static function generateWrapperField (fieldName : String , wrappedField : Dynamic , ? className : String , blacklist : Bool = false ): Null <Field >
165184 {
166185 final pack : Array <String > = [wrappedField .name ];
167186 if (className != null ) pack .unshift (className );
168187
169- inline function getWrapperExpr (args : Array <{name : String }>, ? retType : ComplexType ): Expr
188+ function getWrapperExpr (args : Array <{name : String }>, ? retType : ComplexType ): Expr
170189 {
171190 return if (blacklist )
172191 {
@@ -198,7 +217,8 @@ class BlacklistClassMacro
198217 var wrappedField : ClassField = wrappedField ;
199218 switch (wrappedField .kind )
200219 {
201- case FVar (_ , _ ):
220+ case FVar (read , write ):
221+ trace (read , write );
202222 wrapperKind = FProp (' default' , ' never' , wrappedField .type .toComplexType (), macro $p {pack });
203223 default :
204224 }
0 commit comments