2
2
3
3
const path = require ( 'path' ) ;
4
4
const fs = require ( 'fs' ) ;
5
- const debug = require ( './lib/debug' ) ;
6
5
7
6
const { _deepClone, _assignObject } = require ( './lib/helper' ) ;
8
7
const ClientResolver = require ( './resolver/client' ) ;
9
8
const ModelResolver = require ( './resolver/model' ) ;
10
9
10
+ function readLock ( pkg_dir ) {
11
+ const filepath = path . join ( pkg_dir , '.libraries.json' ) ;
12
+ if ( ! fs . existsSync ( filepath ) ) {
13
+ throw new Error ( 'The `.libraries.json` file could not be found. Please execute "dara install" first.' ) ;
14
+ }
15
+ return JSON . parse ( fs . readFileSync ( filepath , 'utf8' ) ) ;
16
+ }
17
+
18
+ function readModuleMeta ( module_dir , pkg_dir , lock ) {
19
+ if ( ! path . isAbsolute ( module_dir ) ) {
20
+ if ( module_dir . startsWith ( './' ) || module_dir . startsWith ( '../' ) ) {
21
+ module_dir = path . join ( pkg_dir , module_dir ) ;
22
+ } else {
23
+ module_dir = path . join ( pkg_dir , lock [ module_dir ] ) ;
24
+ }
25
+ }
26
+ const filepath = fs . existsSync ( path . join ( module_dir , 'Teafile' ) )
27
+ ? path . join ( module_dir , 'Teafile' )
28
+ : path . join ( module_dir , 'Darafile' ) ;
29
+ return JSON . parse ( fs . readFileSync ( filepath ) ) ;
30
+ }
31
+
32
+ function resolveDependencies ( ast ) {
33
+ const imports = ast . imports ;
34
+ const dependencies = {
35
+ // Package ID : { meta, scope, package_name, client_name, client_alias }
36
+ } ;
37
+ if ( ! imports || ! imports . length ) {
38
+ return dependencies ;
39
+ }
40
+
41
+ const self_client_name = this . config . clientName ? this . config . clientName . toLowerCase ( ) : this . config . client . name . toLowerCase ( ) ;
42
+ const libraries = this . config . libraries ;
43
+ const lock = readLock ( this . config . pkgDir ) ;
44
+ const lang = this . lang ;
45
+ const default_client_name = this . config . client . name ;
46
+ const default_model_dir = this . config . model . dir ;
47
+
48
+ let package_sets = [ ] ;
49
+ let client_sets = [ ] ;
50
+ ast . imports . forEach ( ( item ) => {
51
+ const aliasId = item . lexeme ;
52
+ const meta = readModuleMeta ( libraries [ aliasId ] , this . config . pkgDir , lock ) ;
53
+ const scope = meta . scope ;
54
+ let package_name = meta . name ;
55
+ let client_name = default_client_name ;
56
+ let model_dir = default_model_dir ;
57
+ let lang_config = ! meta [ lang ] ? { } : meta [ lang ] ;
58
+ if ( lang_config . package ) {
59
+ package_name = lang_config . package ;
60
+ }
61
+ if ( lang_config . clientName ) {
62
+ client_name = lang_config . clientName ;
63
+ }
64
+ if ( lang_config . modelDirName ) {
65
+ model_dir = lang_config . modelDirName ;
66
+ }
67
+ // check package name duplication
68
+ if ( package_sets . indexOf ( package_name . toLowerCase ( ) ) > 0 ) {
69
+ throw new Error ( `The package name (${ package_name } ) has been defined in ${ aliasId } dara package.` ) ;
70
+ }
71
+ package_sets . push ( package_name . toLowerCase ( ) ) ;
72
+
73
+ // check client name duplication
74
+ let client_name_lower = client_name . toLowerCase ( ) ;
75
+ let client_alias = '' ;
76
+ if ( client_sets . indexOf ( client_name_lower ) > - 1 || client_name_lower === self_client_name ) {
77
+ client_alias = package_name . split ( '.' ) . join ( '' ) + '->' + client_name . split ( '.' ) . join ( '' ) ;
78
+ } else {
79
+ client_sets . push ( client_name_lower ) ;
80
+ }
81
+ dependencies [ aliasId ] = {
82
+ meta,
83
+ scope,
84
+ package_name,
85
+ client_name,
86
+ client_alias,
87
+ model_dir
88
+ } ;
89
+ } ) ;
90
+ return dependencies ;
91
+ }
92
+
93
+ function getCombinator ( lang , configOriginal , denpendencies ) {
94
+ const config = _deepClone ( configOriginal ) ;
95
+
96
+ // init combinator
97
+ const Combinator = require ( `./langs/${ lang } /combinator` ) ;
98
+ return new Combinator ( config , denpendencies ) ;
99
+ }
100
+
101
+ function resolveAST ( type , ast , globalAST ) {
102
+ const combinator = getCombinator ( this . lang , this . config ) ;
103
+ let resolver ;
104
+ switch ( type ) {
105
+ case 'client' :
106
+ resolver = new ClientResolver ( ast , combinator , ast ) ;
107
+ break ;
108
+ case 'model' :
109
+ resolver = new ModelResolver ( ast , combinator , globalAST ) ;
110
+ break ;
111
+ }
112
+ const objectItem = resolver . resolve ( ) ;
113
+ objectItem . includeList = combinator . includeList ;
114
+ objectItem . includeModelList = combinator . includeModelList ;
115
+ return objectItem ;
116
+ }
117
+
11
118
class Generator {
12
119
constructor ( meta = { } , lang = 'php' ) {
13
120
if ( ! meta . outputDir ) {
14
121
throw new Error ( '`option.outputDir` should not empty' ) ;
15
122
}
16
123
this . lang = lang ;
17
- this . initConfig ( meta ) ;
124
+ const langDir = path . join ( __dirname , `./langs/${ lang } /` ) ;
125
+ if ( ! fs . existsSync ( langDir ) ) {
126
+ throw new Error ( `Not supported language : ${ lang } ` ) ;
127
+ }
128
+ const lang_config = require ( `./langs/${ lang } /config` ) ;
129
+ const common_config = _deepClone ( require ( './langs/common/config' ) ) ;
130
+ const config = {
131
+ dir : meta . outputDir ,
132
+ } ;
133
+ const meta_lang_config = ! meta [ lang ] ? { } : meta [ lang ] ;
134
+ this . config = _assignObject ( config , common_config , lang_config , meta , meta_lang_config ) ;
18
135
}
19
136
20
137
visit ( ast ) {
21
- this . imports = this . resolveImports ( ast ) ;
138
+ const dependencies = resolveDependencies . call ( this , ast ) ;
22
139
if ( this . config . clientName ) {
23
140
this . config . client . name = this . config . clientName ;
24
141
}
@@ -29,171 +146,31 @@ class Generator {
29
146
const objects = [ ] ;
30
147
31
148
// combine client code
32
- const clientObjectItem = this . resolve ( 'client' , ast , ast ) ;
149
+ const clientObjectItem = resolveAST . call ( this , 'client' , ast , ast ) ;
33
150
objects . push ( clientObjectItem ) ;
34
151
35
152
// combine model code
36
153
ast . moduleBody . nodes . filter ( ( item ) => {
37
154
return item . type === 'model' ;
38
155
} ) . forEach ( ( model ) => {
39
156
const modelName = model . modelName . lexeme ;
40
- const modelObjectItem = this . resolve ( 'model' , model , ast ) ;
157
+ const modelObjectItem = resolveAST . call ( this , 'model' , model , ast ) ;
41
158
if ( ast . models ) {
42
159
Object . keys ( ast . models ) . filter ( ( key ) => {
43
160
return key . startsWith ( modelName + '.' ) ;
44
161
} ) . forEach ( ( key ) => {
45
162
const subModel = ast . models [ key ] ;
46
- const subModelObjectItem = this . resolve ( 'model' , subModel , ast ) ;
163
+ const subModelObjectItem = resolveAST . call ( this , 'model' , subModel , ast ) ;
47
164
modelObjectItem . subObject . push ( subModelObjectItem ) ;
48
165
} ) ;
49
166
}
50
167
objects . push ( modelObjectItem ) ;
51
168
} ) ;
52
169
53
- const combinator = this . getCombinator ( this . config ) ;
170
+ const combinator = getCombinator ( this . lang , this . config , dependencies ) ;
54
171
combinator . combine ( objects ) ;
55
172
return objects ;
56
173
}
57
-
58
- resolve ( type , ast , globalAST ) {
59
- const combinator = this . getCombinator ( this . config ) ;
60
- let resolver ;
61
- switch ( type ) {
62
- case 'client' :
63
- resolver = new ClientResolver ( ast , combinator , ast ) ;
64
- break ;
65
- case 'model' :
66
- resolver = new ModelResolver ( ast , combinator , globalAST ) ;
67
- break ;
68
- }
69
- const objectItem = resolver . resolve ( ) ;
70
- objectItem . includeList = combinator . includeList ;
71
- objectItem . includeModelList = combinator . includeModelList ;
72
- return objectItem ;
73
- }
74
-
75
- getCombinator ( configOriginal ) {
76
- const config = _deepClone ( configOriginal ) ;
77
-
78
- // init combinator
79
- const Combinator = require ( `./langs/${ this . lang } /combinator` ) ;
80
- return new Combinator ( config , this . imports ) ;
81
- }
82
-
83
- initConfig ( meta ) {
84
- const langDir = path . join ( __dirname , `./langs/${ this . lang } /` ) ;
85
- if ( ! fs . existsSync ( langDir ) ) {
86
- throw new Error ( `Not supported language : ${ this . lang } ` ) ;
87
- }
88
- const langConfig = require ( `./langs/${ this . lang } /config` ) ;
89
-
90
- const config = _deepClone ( require ( './langs/common/config' ) ) ;
91
- _assignObject ( config , {
92
- dir : meta . outputDir ,
93
- } , langConfig , meta ) ;
94
- if ( meta [ this . lang ] ) {
95
- _assignObject ( config , meta [ this . lang ] ) ;
96
- }
97
- this . config = config ;
98
- }
99
-
100
- resolveImports ( ast ) {
101
- const imports = ast . imports ;
102
-
103
- let requirePackage = [ ] ;
104
- let thirdPackageDaraMeta = { } ;
105
- let thirdPackageScope = { } ;
106
- let thirdPackageNamespace = { } ;
107
- let thirdPackageModel = { } ;
108
- let thirdPackageClient = { } ;
109
- let thirdPackageClientAlias = { } ;
110
- let libraries = { } ;
111
-
112
- const selfClientName = this . config . clientName ? this . config . clientName : this . config . client . name ;
113
-
114
- if ( imports . length > 0 ) {
115
- const lockPath = path . join ( this . config . pkgDir , '.libraries.json' ) ;
116
- const lock = JSON . parse ( fs . readFileSync ( lockPath , 'utf8' ) ) ;
117
- let packageNameSet = [ ] ;
118
- let clientNameSet = [ ] ;
119
- Object . keys ( lock ) . forEach ( key => {
120
- const tmp = key . split ( ':' ) ;
121
- const name = tmp [ 1 ] ;
122
- libraries [ name ] = lock [ key ] ;
123
- } ) ;
124
- ast . imports . forEach ( ( item ) => {
125
- const aliasId = item . lexeme ;
126
- const moduleDir = this . config . libraries [ aliasId ] ;
127
- let targetPath ;
128
- if ( moduleDir . startsWith ( './' ) || moduleDir . startsWith ( '../' ) ) {
129
- targetPath = path . join ( this . config . pkgDir , moduleDir ) ;
130
- } else if ( moduleDir . startsWith ( '/' ) ) {
131
- targetPath = moduleDir ;
132
- } else {
133
- targetPath = path . join ( this . config . pkgDir , lock [ moduleDir ] ) ;
134
- }
135
- // get dara meta
136
- const daraFilePath = fs . existsSync ( path . join ( targetPath , 'Teafile' ) )
137
- ? path . join ( targetPath , 'Teafile' )
138
- : path . join ( targetPath , 'Darafile' ) ;
139
- const daraMeta = JSON . parse ( fs . readFileSync ( daraFilePath ) ) ;
140
- thirdPackageDaraMeta [ aliasId ] = daraMeta ;
141
- thirdPackageScope [ aliasId ] = daraMeta . scope ;
142
-
143
- // init package name, client name, model dir name
144
- let packageName , clientName , modelDir ;
145
- if ( daraMeta [ this . lang ] ) {
146
- packageName = daraMeta [ this . lang ] . package ? daraMeta [ this . lang ] . package : daraMeta . name ;
147
- clientName = daraMeta [ this . lang ] . clientName
148
- ? daraMeta [ this . lang ] . clientName
149
- : this . config . client . name ;
150
- modelDir = daraMeta [ this . lang ] . modelDirName
151
- ? daraMeta [ this . lang ] . modelDirName
152
- : this . config . model . dir ;
153
- } else {
154
- packageName = daraMeta . name ;
155
- clientName = this . config . client . name ;
156
- modelDir = this . config . model . dir ;
157
- }
158
-
159
- // resolve third package namespace
160
- if ( packageNameSet . indexOf ( packageName . toLowerCase ( ) ) < 0 ) {
161
- thirdPackageNamespace [ aliasId ] = packageName ;
162
- packageNameSet . push ( packageName . toLowerCase ( ) ) ;
163
- } else {
164
- debug . stack ( 'Duplication namespace' ) ;
165
- }
166
-
167
- // resolve third package model client name
168
- if (
169
- clientNameSet . indexOf ( clientName . toLowerCase ( ) ) > - 1 ||
170
- clientName . toLowerCase ( ) === selfClientName . toLowerCase ( )
171
- ) {
172
- const alias = packageName . split ( '.' ) . join ( '' ) + '->' + clientName . split ( '.' ) . join ( '' ) ;
173
- thirdPackageClientAlias [ aliasId ] = alias ;
174
- thirdPackageClient [ aliasId ] = clientName ;
175
- } else {
176
- thirdPackageClient [ aliasId ] = clientName ;
177
- clientNameSet . push ( clientName . toLowerCase ( ) ) ;
178
- }
179
- if ( daraMeta . releases && daraMeta . releases [ this . lang ] ) {
180
- requirePackage . push ( daraMeta . releases [ this . lang ] ) ;
181
- }
182
- // third package model dir name
183
- thirdPackageModel [ aliasId ] = modelDir ;
184
- } ) ;
185
- }
186
- return {
187
- libraries,
188
- requirePackage,
189
- thirdPackageDaraMeta,
190
- thirdPackageScope,
191
- thirdPackageNamespace,
192
- thirdPackageClient,
193
- thirdPackageClientAlias,
194
- thirdPackageModel,
195
- } ;
196
- }
197
174
}
198
175
199
176
module . exports = Generator ;
0 commit comments