@@ -2,6 +2,7 @@ library angular_spec;
2
2
3
3
import '_specs.dart' ;
4
4
import 'package:angular/utils.dart' ;
5
+ import 'dart:mirrors' ;
5
6
6
7
main () {
7
8
describe ('angular.dart unittests' , () {
@@ -40,4 +41,288 @@ main() {
40
41
}).toThrow ('Unknown function type, expecting 0 to 5 args.' );
41
42
});
42
43
});
44
+
45
+ describe ('angular symbols' , () {
46
+ it ('should not export symbols that we do not know about' , () {
47
+ // Test is failing? Add new symbols to the "ALLOWED_NAMES" list below.
48
+ // But make sure that you intend to export the symbol!
49
+ // Questions? Talk to @jbdeboer
50
+
51
+ _getSymbolsFromLibrary (String libraryName) {
52
+ var names = [];
53
+ var SYMBOL_NAME = new RegExp ('"(.*)"' );
54
+ _unwrapSymbol (sym) => SYMBOL_NAME .firstMatch (sym.toString ()).group (1 );
55
+
56
+ var seen = {};
57
+
58
+ // TODO(deboer): Add types once Dart VM 1.2 is deprecated.
59
+ extractSymbols (/* LibraryMirror */ lib) {
60
+ lib.declarations.forEach ((symbol, _) {
61
+ names.add ([_unwrapSymbol (symbol), _unwrapSymbol (lib.qualifiedName)]);
62
+ });
63
+
64
+ lib.libraryDependencies.forEach ((/* LibraryDependencyMirror */ libDep) {
65
+ LibraryMirror target = libDep.targetLibrary;
66
+ if (! libDep.isExport) return ;
67
+ if (! seen.containsKey (target)) {
68
+ seen[target] = true ;
69
+ extractSymbols (target);
70
+ }
71
+ });
72
+ };
73
+
74
+ var lib = currentMirrorSystem ().findLibrary (new Symbol (libraryName));
75
+
76
+ extractSymbols (lib);
77
+ return names;
78
+ }
79
+
80
+ var names;
81
+ try { // Not impleneted in Dart VM 1.2
82
+ names = _getSymbolsFromLibrary ("angular" );
83
+ } on UnimplementedError catch (e) {
84
+ return ; // Not implemented, quietly skip.
85
+ } catch (e) {
86
+ print ("Error: $e " );
87
+ return ; // On VMes <1.2, quietly skip.
88
+ }
89
+
90
+ var ALLOWED_PREFIXS = [
91
+ "Ng" ,
92
+ "ng" ,
93
+ "Angular" ,
94
+ "_"
95
+ ];
96
+
97
+ // NOTE(deboer): There are a number of symbols that should not be
98
+ // exported in the list. We are working on un-export the symbols.
99
+ var ALLOWED_NAMES = [
100
+ "di.FactoryFn" ,
101
+ "di.Injector" ,
102
+ "di.InvalidBindingError" ,
103
+ "di.Key" ,
104
+ "di.TypeFactory" ,
105
+ "di.Visibility" ,
106
+ "di.NoProviderError" ,
107
+ "di.CircularDependencyError" ,
108
+ "di.ObjectFactory" ,
109
+ "di.Module" ,
110
+ "angular.core.AnnotationMap" ,
111
+ "angular.core.LruCache" ,
112
+ "angular.core.ScopeStats" ,
113
+ "angular.core.ArrayFn" ,
114
+ "angular.core.Interpolation" ,
115
+ "angular.core.LongStackTrace" ,
116
+ "angular.core.Cache" ,
117
+ "angular.core.ExpressionVisitor" ,
118
+ "angular.core.ScopeEvent" ,
119
+ "angular.core.MapFn" ,
120
+ "angular.core.EvalFunction1" ,
121
+ "angular.core.MetadataExtractor" ,
122
+ "angular.core.ExceptionHandler" ,
123
+ "angular.core.ZoneOnTurn" ,
124
+ "angular.core.ZoneOnError" ,
125
+ "angular.core.ScopeDigestTTL" ,
126
+ "angular.core.EvalFunction0" ,
127
+ "angular.core.AnnotationsMap" ,
128
+ "angular.core.RootScope" ,
129
+ "angular.core.CacheStats" ,
130
+ "angular.core.ScopeLocals" ,
131
+ "angular.core.ScopeStreamSubscription" ,
132
+ "angular.core.Interpolate" ,
133
+ "angular.core.NOT_IMPLEMENTED" ,
134
+ "angular.core.Scope" ,
135
+ "angular.core.AttrFieldAnnotation" ,
136
+ "angular.core.UnboundedCache" ,
137
+ "angular.core.ScopeStream" ,
138
+ "angular.core.FilterMap" ,
139
+ "angular.core.AstParser" ,
140
+ "angular.watch_group.FunctionApply" ,
141
+ "angular.watch_group.WatchGroup" ,
142
+ "angular.watch_group.ContextReferenceAST" ,
143
+ "angular.watch_group.ConstantAST" ,
144
+ "angular.watch_group.Watch" ,
145
+ "angular.watch_group.ReactionFn" ,
146
+ "angular.watch_group.ChangeLog" ,
147
+ "angular.watch_group.FieldReadAST" ,
148
+ "angular.watch_group.PureFunctionAST" ,
149
+ "angular.watch_group.PrototypeMap" ,
150
+ "angular.watch_group.CollectionAST" ,
151
+ "angular.watch_group.MethodAST" ,
152
+ "angular.watch_group.AST" ,
153
+ "angular.watch_group.RootWatchGroup" ,
154
+ "angular.core.dom.AnimationResult" ,
155
+ "angular.core.dom.WalkingViewFactory" ,
156
+ "angular.core.dom.ResponseError" ,
157
+ "angular.core.dom.View" ,
158
+ "angular.core.dom.ElementBinder" ,
159
+ "angular.core.dom.NoOpAnimation" ,
160
+ "angular.core.dom.AttributeChanged" ,
161
+ "angular.core.dom.HttpBackend" ,
162
+ "angular.core.dom.HttpDefaults" ,
163
+ "angular.core.dom.TaggedElementBinder" ,
164
+ "angular.core.dom.LocationWrapper" ,
165
+ "angular.core.dom.Cookies" ,
166
+ "angular.core.dom.ElementBinderTreeRef" ,
167
+ "angular.core.dom.EventHandler" ,
168
+ "angular.core.dom.Response" ,
169
+ "angular.core.dom.HttpDefaultHeaders" ,
170
+ "angular.core.dom.Animation" ,
171
+ "angular.core.dom.ViewPort" ,
172
+ "angular.core.dom.TemplateLoader" ,
173
+ "angular.core.dom.RequestErrorInterceptor" ,
174
+ "angular.core.dom.TaggedTextBinder" ,
175
+ "angular.core.dom.Http" ,
176
+ "angular.core.dom.BoundViewFactory" ,
177
+ "angular.core.dom.ElementBinderFactory" ,
178
+ "angular.core.dom.DirectiveMap" ,
179
+ "angular.core.dom.BrowserCookies" ,
180
+ "angular.core.dom.HttpInterceptor" ,
181
+ "angular.core.dom.cloneElements" ,
182
+ "angular.core.dom.EventFunction" ,
183
+ "angular.core.dom.RequestInterceptor" ,
184
+ "angular.core.dom.DefaultTransformDataHttpInterceptor" ,
185
+ "angular.core.dom.HttpResponseConfig" ,
186
+ "angular.core.dom.ElementProbe" ,
187
+ "angular.core.dom.ApplyMapping" ,
188
+ "angular.core.dom.ViewCache" ,
189
+ "angular.core.dom.FieldMetadataExtractor" ,
190
+ "angular.core.dom.Compiler" ,
191
+ "angular.core.dom.HttpResponse" ,
192
+ "angular.core.dom.UrlRewriter" ,
193
+ "angular.core.dom.DirectiveRef" ,
194
+ "angular.core.dom.HttpInterceptors" ,
195
+ "angular.core.dom.forceNewDirectivesAndFilters" ,
196
+ "angular.core.dom.DirectiveSelectorFactory" ,
197
+ "angular.core.dom.ObserverChanged" ,
198
+ "angular.core.dom.TaggingViewFactory" ,
199
+ "angular.core.dom.NodeCursor" ,
200
+ "angular.core.dom.TemplateCache" ,
201
+ "angular.core.dom.ViewFactory" ,
202
+ "angular.core.dom.NullTreeSanitizer" ,
203
+ "angular.core.dom.NodeAttrs" ,
204
+ "angular.core.dom.ElementBinderTree" ,
205
+ "angular.core.dom.WalkingCompiler" ,
206
+ "angular.core.dom.TaggingCompiler" ,
207
+ "angular.core.dom.DirectiveSelector" ,
208
+ "angular.core.parser.BoundGetter" ,
209
+ "angular.core.parser.LocalsWrapper" ,
210
+ "angular.core.parser.Getter" ,
211
+ "angular.core.parser.Parser" ,
212
+ "angular.core.parser.ParserBackend" ,
213
+ "angular.core.parser.BoundSetter" ,
214
+ "angular.core.parser.Setter" ,
215
+ "angular.core.parser.syntax.LiteralObject" ,
216
+ "angular.core.parser.syntax.CallMember" ,
217
+ "angular.core.parser.syntax.Filter" ,
218
+ "angular.core.parser.syntax.defaultFilterMap" ,
219
+ "angular.core.parser.syntax.BoundExpression" ,
220
+ "angular.core.parser.syntax.AccessMember" ,
221
+ "angular.core.parser.syntax.Expression" ,
222
+ "angular.core.parser.syntax.AccessScope" ,
223
+ "angular.core.parser.syntax.Assign" ,
224
+ "angular.core.parser.syntax.AccessKeyed" ,
225
+ "angular.core.parser.syntax.CallScope" ,
226
+ "angular.core.parser.syntax.CallFunction" ,
227
+ "angular.core.parser.syntax.Conditional" ,
228
+ "angular.core.parser.syntax.Binary" ,
229
+ "angular.core.parser.syntax.Chain" ,
230
+ "angular.core.parser.syntax.Prefix" ,
231
+ "angular.core.parser.syntax.Literal" ,
232
+ "angular.core.parser.syntax.LiteralString" ,
233
+ "angular.core.parser.syntax.LiteralArray" ,
234
+ "angular.core.parser.syntax.LiteralPrimitive" ,
235
+ "angular.core.parser.syntax.Visitor" ,
236
+ "angular.core.parser.dynamic_parser.DynamicExpression" ,
237
+ "angular.core.parser.dynamic_parser.ClosureMap" ,
238
+ "angular.core.parser.dynamic_parser.DynamicParser" ,
239
+ "angular.core.parser.dynamic_parser.DynamicParserBackend" ,
240
+ "angular.core.parser.static_parser.StaticParserFunctions" ,
241
+ "angular.core.parser.static_parser.StaticExpression" ,
242
+ "angular.core.parser.static_parser.StaticParser" ,
243
+ "angular.core.parser.lexer.Scanner" ,
244
+ "angular.core.parser.lexer.OPERATORS" ,
245
+ "angular.core.parser.lexer.NumberToken" ,
246
+ "angular.core.parser.lexer.Token" ,
247
+ "angular.core.parser.lexer.IdentifierToken" ,
248
+ "angular.core.parser.lexer.StringToken" ,
249
+ "angular.core.parser.lexer.CharacterToken" ,
250
+ "angular.core.parser.lexer.Lexer" ,
251
+ "angular.core.parser.lexer.KEYWORDS" ,
252
+ "angular.core.parser.lexer.OperatorToken" ,
253
+ "angular.directive.ItemEval" ,
254
+ "angular.directive.OptionValueDirective" ,
255
+ "angular.directive.InputSelectDirective" ,
256
+ "angular.directive.InputTextLikeDirective" ,
257
+ "angular.directive.InputNumberLikeDirective" ,
258
+ "angular.directive.ContentEditableDirective" ,
259
+ "angular.directive.InputCheckboxDirective" ,
260
+ "angular.directive.InputRadioDirective" ,
261
+ "angular.filter.JsonFilter" ,
262
+ "angular.filter.Equals" ,
263
+ "angular.filter.Mapper" ,
264
+ "angular.filter.FilterFilter" ,
265
+ "angular.filter.NumberFilter" ,
266
+ "angular.filter.DateFilter" ,
267
+ "angular.filter.LowercaseFilter" ,
268
+ "angular.filter.UppercaseFilter" ,
269
+ "angular.filter.OrderByFilter" ,
270
+ "angular.filter.CurrencyFilter" ,
271
+ "angular.filter.LimitToFilter" ,
272
+ "angular.filter.Predicate" ,
273
+ "angular.routing.RouteInitializerFn" ,
274
+ "angular.routing.RouteProvider" ,
275
+ "angular.routing.RouteInitializer" ,
276
+ "angular.routing.RouteViewFactory" ,
277
+ "route.client.RouteHandle" ,
278
+ "route.client.RouteEnterEvent" ,
279
+ "route.client.RouteStartEvent" ,
280
+ "route.client.Router" ,
281
+ "route.client.RouteEvent" ,
282
+ "route.client.RouteLeaveEventHandler" ,
283
+ "route.client.Route" ,
284
+ "route.client.RouteImpl" ,
285
+ "route.client.RouteLeaveEvent" ,
286
+ "route.client.RoutePreEnterEventHandler" ,
287
+ "route.client.RoutePreEnterEvent" ,
288
+ "route.client.Routable" ,
289
+ "route.client.RouteEnterEventHandler" ,
290
+ "url_matcher.UrlMatcher" ,
291
+ "url_matcher.UrlMatch" ,
292
+ "dirty_checking_change_detector.FieldGetter" ,
293
+ "dirty_checking_change_detector.DirtyCheckingChangeDetector" ,
294
+ "dirty_checking_change_detector.DirtyCheckingRecord" ,
295
+ "dirty_checking_change_detector.ItemRecord" ,
296
+ "dirty_checking_change_detector.KeyValueRecord" ,
297
+ "dirty_checking_change_detector.DuplicateMap" ,
298
+ "dirty_checking_change_detector.GetterCache" ,
299
+ "dirty_checking_change_detector.DirtyCheckingChangeDetectorGroup"
300
+ ];
301
+
302
+ var _nameMap = {};
303
+ ALLOWED_NAMES .forEach ((x) => _nameMap[x] = true );
304
+
305
+ assertSymbolNameIsOk (List nameInfo) {
306
+ String name = nameInfo[0 ];
307
+ String libName = nameInfo[1 ];
308
+
309
+ if (ALLOWED_PREFIXS .any ((prefix) => name.startsWith (prefix))) return ;
310
+
311
+ var key = "$libName .$name " ;
312
+ if (_nameMap.containsKey (key)) {
313
+ _nameMap[key] = false ;
314
+ return ;
315
+ }
316
+
317
+ throw "Symbol $key is exported thru the angular library, but it shouldn't be" ;
318
+ };
319
+
320
+ names.forEach (assertSymbolNameIsOk);
321
+
322
+ // If there are keys that no longer need to be in the ALLOWED_NAMES list, complain.
323
+ _nameMap.forEach ((k,v) {
324
+ if (v) print ("angular_spec.dart: Unused ALLOWED_NAMES key $k " );
325
+ });
326
+ });
327
+ });
43
328
}
0 commit comments