77var path = require ( 'path' ) ;
88
99var LocalModulesHelpers = require ( "webpack/lib/dependencies/LocalModulesHelpers" ) ;
10- var LocalModuleDependency = require ( "webpack/lib/dependencies/LocalModuleDependency" ) ;
1110var NullFactory = require ( "webpack/lib/NullFactory" ) ;
1211var ModuleParserHelpers = require ( "webpack/lib/ModuleParserHelpers" ) ;
1312var RequireHeaderDependency = require ( "webpack/lib/dependencies/RequireHeaderDependency" ) ;
1413
1514var AngularModuleDependency = require ( './AngularModuleDependency' ) ;
1615var AngularModuleDefinition = require ( './AngularModuleDefinition' ) ;
1716
18- function AngularPlugin ( ) { }
17+ function AngularPlugin ( ) {
18+ }
1919
2020module . exports = AngularPlugin ;
2121
22+ function bindCallbackMethod ( source , plugname , obj , method ) {
23+ source . plugin ( plugname , method . bind ( obj , source ) ) ;
24+ }
25+
26+ function containsSlash ( str ) {
27+ return str . indexOf ( "/" ) >= 0 || str . indexOf ( "\\" ) >= 0 ;
28+ }
29+
30+ // Try to resolve a file of the form /somepath/module/module
31+ // (calling it modmod for want of a better term)
32+ function resolveModModFile ( resolver , request , callback ) {
33+ var joined = path . join ( request . request , request . request ) ;
34+ return resolver . doResolve ( "file" , {
35+ path : request . path ,
36+ request : joined ,
37+ query : request . query
38+ } , callback , true ) ;
39+ }
40+
41+ function requestIsModModFile ( request ) {
42+ if ( containsSlash ( request . request ) || ! request . file ) {
43+ return false ;
44+ }
45+ var starting = request . path . length - request . request . length ;
46+ var match = request . path . lastIndexOf ( request . request ) ;
47+ return match === starting &&
48+ ( request . path [ starting - 1 ] === '/' || request . path [ starting - 1 ] === '\\' ) ;
49+ }
2250
2351AngularPlugin . prototype = {
2452 constructor : AngularPlugin ,
2553
2654 // This is the entrypoint that is called when the plugin is added to a
2755 // compiler
2856 apply : function ( compiler ) {
29- compiler . plugin ( "compilation" , this . addDependencyFactories . bind ( this ) ) ;
30- compiler . parser . plugin ( 'expression angular' , function ( ) {
31- return ModuleParserHelpers . addParsedVariable ( this , 'angular' ,
32- "require('angular')" ) ;
33- } ) ;
34- compiler . parser . plugin ( 'call angular.module' ,
35- this . parseModuleCall . bind ( this , compiler . parser ) ) ;
36- compiler . resolvers . normal . plugin ( 'module-module' ,
37- this . resolveModule . bind ( this , compiler . resolvers . normal ) ) ;
57+ bindCallbackMethod ( compiler , "compilation" ,
58+ this , this . addDependencyFactories ) ;
59+ bindCallbackMethod ( compiler . parser , "expression angular" ,
60+ this , this . addAngularVariable ) ;
61+ bindCallbackMethod ( compiler . parser , "call angular.module" ,
62+ this , this . parseModuleCall ) ;
63+ bindCallbackMethod ( compiler . resolvers . normal , "module-module" ,
64+ this , this . resolveModule ) ;
3865 } ,
3966
67+ // #### Plugin Callbacks
68+
4069 // This sets up the compiler with the right dependency module factories
41- addDependencyFactories : function ( compilation , params ) {
70+ addDependencyFactories : function ( compiler , compilation , params ) {
4271 compilation . dependencyFactories . set ( AngularModuleDependency ,
4372 params . normalModuleFactory ) ;
4473 compilation . dependencyTemplates . set ( AngularModuleDependency ,
@@ -49,89 +78,126 @@ AngularPlugin.prototype = {
4978 new AngularModuleDefinition . Template ( ) ) ;
5079 } ,
5180
81+ // This injects the angular module wherever it's used.
82+ addAngularVariable : function ( parser ) {
83+ return ModuleParserHelpers . addParsedVariable ( parser , 'angular' , "require('angular')" ) ;
84+ } ,
85+
5286 // Each call to `angular.module()` is analysed here
5387 parseModuleCall : function ( parser , expr ) {
54- var mod , deps ;
55- ModuleParserHelpers . addParsedVariable ( parser , 'angular' ,
56- "require('angular')" ) ;
57- switch ( expr . arguments . length ) {
58- // A single argument is the equivalent of `require()`
59- case 1 :
60- mod = parser . evaluateExpression ( expr . arguments [ 0 ] ) ;
61- return this . _addDependencyForParameter ( parser , expr , mod ) ;
62- // 2 arguments mean a module definition if the 2nd is an array.
63- case 2 :
64- mod = parser . evaluateExpression ( expr . arguments [ 0 ] ) ;
65- // TODO: should we check the module name?
66- this . _addModuleDefinition ( parser , expr , mod ) ;
67- deps = parser . evaluateExpression ( expr . arguments [ 1 ] ) ;
68- if ( deps . items ) {
69- return deps . items . every (
70- this . _addDependencyForParameter . bind ( this , parser , expr ) ) ;
71- }
72- return this . _addDependencyForParameter ( parser , expr , mod ) ;
73- // 3 arguments must be a module definition
74- case 3 :
75- mod = parser . evaluateExpression ( expr . arguments [ 0 ] ) ;
76- // TODO: should we check the module name?
77- this . _addModuleDefinition ( parser , expr , mod ) ;
78- deps = parser . evaluateExpression ( expr . arguments [ 1 ] ) ;
79- return deps . items . every (
80- this . _addDependencyForParameter . bind ( this , parser , expr ) ) ;
88+ this . addAngularVariable ( parser ) ;
89+ switch ( expr . arguments . length ) {
90+ case 1 : return this . _parseModuleCallSingleArgument ( parser , expr ) ;
91+ case 2 : return this . _parseModuleCallTwoArgument ( parser , expr ) ;
92+ case 3 : return this . _parseModuleCallThreeArgument ( parser , expr ) ;
8193 default :
8294 console . warn ( "Don't recognise angular.module() with " +
8395 expr . arguments . length + " args" ) ;
84- }
96+ }
8597 } ,
8698
99+ // Additional module resolving specific to angular modules.
100+ //
101+ // We're trying to follow as many existing conventions as possible. Including:
102+ // - dots as path separators
103+ // - camelCase module names convert to dashed file names
104+ // - module, directory and file names all the same.
105+ // - files containing multiple modules (shared prefix)
106+ //
87107 resolveModule : function ( resolver , request , callback ) {
88- var fs = resolver . fileSystem ;
89- var i = request . request . indexOf ( "." ) ;
90- if ( i < 0 ) {
91- // Try resolving a file of the form module/module
92- return resolver . doResolve ( "file" , {
93- path : request . path ,
94- request : path . join ( request . request , request . request ) ,
95- query : request . query
96- } , callback , true ) ;
108+ if ( containsSlash ( request . request ) ) {
109+ return callback ( ) ;
97110 }
98- // Try treating `.` as a path separator
99- var moduleName = request . request . substr ( 0 , i ) ;
100- var remainingRequest = request . request . substr ( i + 1 ) ;
101- var modulePath = resolver . join ( request . path , moduleName ) ;
102- fs . stat ( modulePath , function ( err , stat ) {
103- if ( err || ! stat ) {
104- if ( callback . log ) {
105- callback . log ( modulePath + " doesn't exist (ng module as directory)" ) ;
111+ var split = request . request . split ( '.' ) ;
112+ if ( split . length === 1 ) {
113+ if ( ! requestIsModModFile ( request ) ) {
114+ return resolveModModFile ( resolver , request , callback ) ;
115+ }
116+ } else {
117+ // Try treating `.` as a path separator, but in a non-greedy way.
118+ // There are lots of options here because we allow the file name to be
119+ // just a prefix.
120+ // prefer the segments to be directories and prefer the full name to be
121+ // used.
122+ var pairs = [ ] ;
123+ for ( var j = 0 ; j > ( 0 - split . length ) ; j -- ) {
124+ var cropped = split . slice ( 0 , j || undefined ) ;
125+ for ( var i = 0 ; i < cropped . length ; i ++ ) {
126+ pairs . push ( { front : cropped . slice ( 0 , i ) , back : cropped . slice ( i ) } ) ;
106127 }
107- return callback ( ) ;
108128 }
109- if ( stat . isDirectory ( ) ) {
110- var types = request . directory ? "directory" : [ "file" , "directory" ] ;
111- return resolver . doResolve ( types , {
112- path : modulePath ,
113- request : remainingRequest ,
129+ pairs . shift ( ) ;
130+ var requests = pairs . map ( function ( p ) {
131+ return {
132+ path : path . join . apply ( path , [ request . path ] . concat ( p . front ) ) ,
133+ request : p . back . join ( '.' ) ,
114134 query : request . query
115- } , callback , true ) ;
116- }
117- if ( callback . log ) {
118- callback . log ( modulePath + " is not a directory (ng module as directory)" ) ;
119- }
120- return callback ( ) ;
121- } ) ;
135+ } ;
136+ } ) ;
137+
138+ return resolver . forEachBail ( requests , function ( req , cb ) {
139+ return resolver . doResolve ( [ "file" , "directory" ] , req , cb , true ) ;
140+ } , function ( err , resolved ) {
141+ if ( err || ! resolved ) {
142+ return callback ( err ) ;
143+ }
144+ if ( resolved . file ) {
145+ // We're taking this as resolved. It should contain other modules with
146+ // this prefix
147+ return resolver . doResolve ( "result" , resolved , callback ) ;
148+ }
149+ if ( callback . log ) {
150+ callback . log ( " is not an angular module" ) ;
151+ }
152+ callback ( ) ;
153+ } ) ;
154+ }
155+ return callback ( ) ;
122156 } ,
123157
158+ // #### Private Methods
159+
160+ // A single argument is the equivalent of `require()`
161+ // angular.module(name)
162+ _parseModuleCallSingleArgument : function ( parser , expr ) {
163+ var mod = parser . evaluateExpression ( expr . arguments [ 0 ] ) ;
164+ return this . _addDependency ( parser , expr , mod ) ;
165+ } ,
166+
167+ // 2 arguments mean a module definition if the 2nd is an array.
168+ // angular.module(name, requires)
169+ // angular.module(name, configFn)
170+ _parseModuleCallTwoArgument : function ( parser , expr ) {
171+ var mod = parser . evaluateExpression ( expr . arguments [ 0 ] ) ;
172+ var deps = parser . evaluateExpression ( expr . arguments [ 1 ] ) ;
173+ this . _addModuleDefinition ( parser , expr , mod ) ;
174+ if ( deps . items ) {
175+ return deps . items . every (
176+ this . _addDependency . bind ( this , parser , expr ) ) ;
177+ }
178+ return this . _addDependency ( parser , expr , mod ) ;
179+ } ,
180+
181+ // 3 arguments must be a module definition
182+ // angular.module(name, requires, configFn)
183+ _parseModuleCallThreeArgument : function ( parser , expr ) {
184+ var mod = parser . evaluateExpression ( expr . arguments [ 0 ] ) ;
185+ var deps = parser . evaluateExpression ( expr . arguments [ 1 ] ) ;
186+ this . _addModuleDefinition ( parser , expr , mod ) ;
187+ return deps . items . every (
188+ this . _addDependency . bind ( this , parser , expr ) ) ;
189+ } ,
124190
125191 _addModuleDefinition : function ( parser , expr , mod ) {
126- var dep = new AngularModuleDefinition ( expr . range ) ;
192+ var dep = new AngularModuleDefinition ( expr . range , mod . string ) ;
127193 dep . loc = expr . loc ;
128194 dep . localModule = LocalModulesHelpers . addLocalModule ( parser . state , mod . string ) ;
129195 parser . state . current . addDependency ( dep ) ;
130196 return true ;
131197 } ,
132198
133199 // A dependency (module) has been found
134- _addDependencyForParameter : function ( parser , expr , param ) {
200+ _addDependency : function ( parser , expr , param ) {
135201 if ( param . isConditional ( ) ) {
136202 // TODO: not sure what this will output
137203 parser . state . current . addDependency (
@@ -148,16 +214,12 @@ AngularPlugin.prototype = {
148214 }
149215 if ( param . isString ( ) ) {
150216 var dep ;
151- var localModule = LocalModulesHelpers . getLocalModule ( parser . state ,
152- param . string ) ;
153- if ( localModule ) {
154- dep = new LocalModuleDependency ( localModule , expr . range ) ;
155- dep . loc = expr . loc ;
156- parser . state . current . addDependency ( dep ) ;
217+ var localModule = LocalModulesHelpers . getLocalModule ( parser . state , param . string ) ;
218+ if ( localModule ) {
157219 return true ;
158220 }
159221 dep = new AngularModuleDependency ( param . string , param . range ) ;
160- dep . log = expr . loc ;
222+ dep . loc = param . loc ;
161223 parser . state . current . addDependency ( dep ) ;
162224 return true ;
163225 }
0 commit comments