@@ -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,289 @@ 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
+ // Comments on each symbols below.
100
+ var ALLOWED_NAMES = [
101
+ "di.FactoryFn" ,
102
+ "di.Injector" ,
103
+ "di.InvalidBindingError" ,
104
+ "di.Key" , // common name, should be removed.
105
+ "di.TypeFactory" ,
106
+ "di.Visibility" ,
107
+ "di.NoProviderError" ,
108
+ "di.CircularDependencyError" ,
109
+ "di.ObjectFactory" ,
110
+ "di.Module" ,
111
+ "angular.core.AnnotationMap" ,
112
+ "angular.core.LruCache" , // internal?
113
+ "angular.core.ScopeStats" ,
114
+ "angular.core.ArrayFn" , // internal?
115
+ "angular.core.Interpolation" ,
116
+ "angular.core.LongStackTrace" , // internal?
117
+ "angular.core.Cache" , // internal?
118
+ "angular.core.ExpressionVisitor" , // internal?
119
+ "angular.core.ScopeEvent" ,
120
+ "angular.core.MapFn" , // internal?
121
+ "angular.core.EvalFunction1" , // internal?
122
+ "angular.core.MetadataExtractor" , // internal?
123
+ "angular.core.ExceptionHandler" ,
124
+ "angular.core.ZoneOnTurn" , // internal?
125
+ "angular.core.ZoneOnError" , // internal?
126
+ "angular.core.ScopeDigestTTL" ,
127
+ "angular.core.EvalFunction0" , // internal?
128
+ "angular.core.AnnotationsMap" , // internal?
129
+ "angular.core.RootScope" ,
130
+ "angular.core.CacheStats" ,
131
+ "angular.core.ScopeLocals" ,
132
+ "angular.core.ScopeStreamSubscription" ,
133
+ "angular.core.Interpolate" ,
134
+ "angular.core.NOT_IMPLEMENTED" , // internal?
135
+ "angular.core.Scope" ,
136
+ "angular.core.AttrFieldAnnotation" ,
137
+ "angular.core.UnboundedCache" , // internal?
138
+ "angular.core.ScopeStream" , // internal?
139
+ "angular.core.FilterMap" , // internal?
140
+ "angular.core.AstParser" , // internal?
141
+ "angular.watch_group.FunctionApply" , // internal?
142
+ "angular.watch_group.WatchGroup" , // internal?
143
+ "angular.watch_group.ContextReferenceAST" , // internal?
144
+ "angular.watch_group.ConstantAST" , // internal?
145
+ "angular.watch_group.Watch" ,
146
+ "angular.watch_group.ReactionFn" , // internal?
147
+ "angular.watch_group.ChangeLog" ,
148
+ "angular.watch_group.FieldReadAST" , // internal?
149
+ "angular.watch_group.PureFunctionAST" , // internal?
150
+ "angular.watch_group.PrototypeMap" , // internal?
151
+ "angular.watch_group.CollectionAST" , // internal?
152
+ "angular.watch_group.MethodAST" , // internal?
153
+ "angular.watch_group.AST" , // internal?
154
+ "angular.watch_group.RootWatchGroup" ,
155
+ "angular.core.dom.AnimationResult" ,
156
+ "angular.core.dom.WalkingViewFactory" , // internal?
157
+ "angular.core.dom.ResponseError" ,
158
+ "angular.core.dom.View" ,
159
+ "angular.core.dom.ElementBinder" , // internal?
160
+ "angular.core.dom.NoOpAnimation" ,
161
+ "angular.core.dom.AttributeChanged" ,
162
+ "angular.core.dom.HttpBackend" ,
163
+ "angular.core.dom.HttpDefaults" ,
164
+ "angular.core.dom.TaggedElementBinder" , // internal?
165
+ "angular.core.dom.LocationWrapper" ,
166
+ "angular.core.dom.Cookies" ,
167
+ "angular.core.dom.ElementBinderTreeRef" , // internal?
168
+ "angular.core.dom.EventHandler" ,
169
+ "angular.core.dom.Response" ,
170
+ "angular.core.dom.HttpDefaultHeaders" ,
171
+ "angular.core.dom.Animation" ,
172
+ "angular.core.dom.ViewPort" ,
173
+ "angular.core.dom.TemplateLoader" ,
174
+ "angular.core.dom.RequestErrorInterceptor" ,
175
+ "angular.core.dom.TaggedTextBinder" , // internal?
176
+ "angular.core.dom.Http" ,
177
+ "angular.core.dom.BoundViewFactory" , // internal?
178
+ "angular.core.dom.ElementBinderFactory" , // internal?
179
+ "angular.core.dom.DirectiveMap" , // internal?
180
+ "angular.core.dom.BrowserCookies" ,
181
+ "angular.core.dom.HttpInterceptor" ,
182
+ "angular.core.dom.cloneElements" , // internal?
183
+ "angular.core.dom.EventFunction" , // internal?
184
+ "angular.core.dom.RequestInterceptor" ,
185
+ "angular.core.dom.DefaultTransformDataHttpInterceptor" ,
186
+ "angular.core.dom.HttpResponseConfig" ,
187
+ "angular.core.dom.ElementProbe" ,
188
+ "angular.core.dom.ApplyMapping" , // internal?
189
+ "angular.core.dom.ViewCache" , // internal?
190
+ "angular.core.dom.FieldMetadataExtractor" , // internal?
191
+ "angular.core.dom.Compiler" ,
192
+ "angular.core.dom.HttpResponse" ,
193
+ "angular.core.dom.UrlRewriter" ,
194
+ "angular.core.dom.DirectiveRef" ,
195
+ "angular.core.dom.HttpInterceptors" ,
196
+ "angular.core.dom.forceNewDirectivesAndFilters" , // internal?
197
+ "angular.core.dom.DirectiveSelectorFactory" , // internal?
198
+ "angular.core.dom.ObserverChanged" ,
199
+ "angular.core.dom.TaggingViewFactory" , // internal?
200
+ "angular.core.dom.NodeCursor" , // internal?
201
+ "angular.core.dom.TemplateCache" , // internal?
202
+ "angular.core.dom.ViewFactory" ,
203
+ "angular.core.dom.NullTreeSanitizer" ,
204
+ "angular.core.dom.NodeAttrs" ,
205
+ "angular.core.dom.ElementBinderTree" , // internal?
206
+ "angular.core.dom.WalkingCompiler" , // internal?
207
+ "angular.core.dom.TaggingCompiler" , // internal?
208
+ "angular.core.dom.DirectiveSelector" , // internal?
209
+ "angular.core.parser.BoundGetter" , // internal?
210
+ "angular.core.parser.LocalsWrapper" , // internal?
211
+ "angular.core.parser.Getter" , // common name
212
+ "angular.core.parser.Parser" ,
213
+ "angular.core.parser.ParserBackend" ,
214
+ "angular.core.parser.BoundSetter" ,
215
+ "angular.core.parser.Setter" , // common name
216
+ "angular.core.parser.syntax.LiteralObject" , // evenything in syntax should be private
217
+ "angular.core.parser.syntax.CallMember" ,
218
+ "angular.core.parser.syntax.Filter" ,
219
+ "angular.core.parser.syntax.defaultFilterMap" ,
220
+ "angular.core.parser.syntax.BoundExpression" ,
221
+ "angular.core.parser.syntax.AccessMember" ,
222
+ "angular.core.parser.syntax.Expression" ,
223
+ "angular.core.parser.syntax.AccessScope" ,
224
+ "angular.core.parser.syntax.Assign" ,
225
+ "angular.core.parser.syntax.AccessKeyed" ,
226
+ "angular.core.parser.syntax.CallScope" ,
227
+ "angular.core.parser.syntax.CallFunction" ,
228
+ "angular.core.parser.syntax.Conditional" ,
229
+ "angular.core.parser.syntax.Binary" ,
230
+ "angular.core.parser.syntax.Chain" ,
231
+ "angular.core.parser.syntax.Prefix" ,
232
+ "angular.core.parser.syntax.Literal" ,
233
+ "angular.core.parser.syntax.LiteralString" ,
234
+ "angular.core.parser.syntax.LiteralArray" ,
235
+ "angular.core.parser.syntax.LiteralPrimitive" ,
236
+ "angular.core.parser.syntax.Visitor" ,
237
+ "angular.core.parser.dynamic_parser.DynamicExpression" ,
238
+ "angular.core.parser.dynamic_parser.ClosureMap" ,
239
+ "angular.core.parser.dynamic_parser.DynamicParser" ,
240
+ "angular.core.parser.dynamic_parser.DynamicParserBackend" ,
241
+ "angular.core.parser.static_parser.StaticParserFunctions" ,
242
+ "angular.core.parser.static_parser.StaticExpression" ,
243
+ "angular.core.parser.static_parser.StaticParser" ,
244
+ "angular.core.parser.lexer.Scanner" , // everything in lexer should be private
245
+ "angular.core.parser.lexer.OPERATORS" ,
246
+ "angular.core.parser.lexer.NumberToken" ,
247
+ "angular.core.parser.lexer.Token" ,
248
+ "angular.core.parser.lexer.IdentifierToken" ,
249
+ "angular.core.parser.lexer.StringToken" ,
250
+ "angular.core.parser.lexer.CharacterToken" ,
251
+ "angular.core.parser.lexer.Lexer" ,
252
+ "angular.core.parser.lexer.KEYWORDS" ,
253
+ "angular.core.parser.lexer.OperatorToken" ,
254
+ "angular.directive.ItemEval" ,
255
+ "angular.directive.OptionValueDirective" ,
256
+ "angular.directive.InputSelectDirective" ,
257
+ "angular.directive.InputTextLikeDirective" ,
258
+ "angular.directive.InputNumberLikeDirective" ,
259
+ "angular.directive.ContentEditableDirective" ,
260
+ "angular.directive.InputCheckboxDirective" ,
261
+ "angular.directive.InputRadioDirective" ,
262
+ "angular.filter.JsonFilter" ,
263
+ "angular.filter.Equals" ,
264
+ "angular.filter.Mapper" ,
265
+ "angular.filter.FilterFilter" ,
266
+ "angular.filter.NumberFilter" ,
267
+ "angular.filter.DateFilter" ,
268
+ "angular.filter.LowercaseFilter" ,
269
+ "angular.filter.UppercaseFilter" ,
270
+ "angular.filter.OrderByFilter" ,
271
+ "angular.filter.CurrencyFilter" ,
272
+ "angular.filter.LimitToFilter" ,
273
+ "angular.filter.Predicate" ,
274
+ "angular.routing.RouteInitializerFn" ,
275
+ "angular.routing.RouteProvider" ,
276
+ "angular.routing.RouteInitializer" ,
277
+ "angular.routing.RouteViewFactory" ,
278
+ "route.client.RouteHandle" ,
279
+ "route.client.RouteEnterEvent" ,
280
+ "route.client.RouteStartEvent" ,
281
+ "route.client.Router" ,
282
+ "route.client.RouteEvent" ,
283
+ "route.client.RouteLeaveEventHandler" ,
284
+ "route.client.Route" ,
285
+ "route.client.RouteImpl" ,
286
+ "route.client.RouteLeaveEvent" ,
287
+ "route.client.RoutePreEnterEventHandler" ,
288
+ "route.client.RoutePreEnterEvent" ,
289
+ "route.client.Routable" ,
290
+ "route.client.RouteEnterEventHandler" ,
291
+ "url_matcher.UrlMatcher" ,
292
+ "url_matcher.UrlMatch" ,
293
+ "dirty_checking_change_detector.FieldGetter" , // everything in change detector should be private
294
+ "dirty_checking_change_detector.DirtyCheckingChangeDetector" ,
295
+ "dirty_checking_change_detector.DirtyCheckingRecord" ,
296
+ "dirty_checking_change_detector.ItemRecord" ,
297
+ "dirty_checking_change_detector.KeyValueRecord" ,
298
+ "dirty_checking_change_detector.DuplicateMap" ,
299
+ "dirty_checking_change_detector.GetterCache" ,
300
+ "dirty_checking_change_detector.DirtyCheckingChangeDetectorGroup"
301
+ ];
302
+
303
+ var _nameMap = {};
304
+ ALLOWED_NAMES .forEach ((x) => _nameMap[x] = true );
305
+
306
+ assertSymbolNameIsOk (List nameInfo) {
307
+ String name = nameInfo[0 ];
308
+ String libName = nameInfo[1 ];
309
+
310
+ if (ALLOWED_PREFIXS .any ((prefix) => name.startsWith (prefix))) return ;
311
+
312
+ var key = "$libName .$name " ;
313
+ if (_nameMap.containsKey (key)) {
314
+ _nameMap[key] = false ;
315
+ return ;
316
+ }
317
+
318
+ throw "Symbol $key is exported thru the angular library, but it shouldn't be" ;
319
+ };
320
+
321
+ names.forEach (assertSymbolNameIsOk);
322
+
323
+ // If there are keys that no longer need to be in the ALLOWED_NAMES list, complain.
324
+ _nameMap.forEach ((k,v) {
325
+ if (v) print ("angular_spec.dart: Unused ALLOWED_NAMES key $k " );
326
+ });
327
+ });
328
+ });
43
329
}
0 commit comments