|
1 |
| -import { union } from 'lodash' |
| 1 | +import { union, defaultsDeep } from 'lodash' |
2 | 2 | import { FabrixApp } from './'
|
3 | 3 | import * as mkdirp from 'mkdirp'
|
4 | 4 | import { Templates } from './'
|
@@ -115,8 +115,8 @@ export const Core = {
|
115 | 115 | /**
|
116 | 116 | * Instantiate resource classes and bind resource methods
|
117 | 117 | */
|
118 |
| - bindResourceMethods(app: FabrixApp, defaults: string[]): void { |
119 |
| - defaults.forEach(resource => { |
| 118 | + bindResourceMethods(app: FabrixApp, resources: string[]): void { |
| 119 | + resources.forEach(resource => { |
120 | 120 | try {
|
121 | 121 | app[resource] = Core.bindMethods(app, resource)
|
122 | 122 | }
|
@@ -148,42 +148,112 @@ export const Core = {
|
148 | 148 | return props
|
149 | 149 | },
|
150 | 150 |
|
| 151 | + /** |
| 152 | + * Get the property names of an Object |
| 153 | + */ |
| 154 | + getPropertyNames(obj) { |
| 155 | + return Object.getOwnPropertyNames(obj.prototype) |
| 156 | + }, |
| 157 | + |
| 158 | + /** |
| 159 | + * If the object has a prototype property |
| 160 | + */ |
| 161 | + hasPrototypeProperty(obj, proto) { |
| 162 | + return obj.prototype.hasOwnProperty(proto) |
| 163 | + }, |
| 164 | + |
| 165 | + /** |
| 166 | + * Merge the Prototype of uninitiated classes |
| 167 | + */ |
| 168 | + mergePrototype(obj, next, proto) { |
| 169 | + obj.prototype[proto] = next.prototype[proto] |
| 170 | + }, |
| 171 | + |
151 | 172 | /**
|
152 | 173 | * Merge the app api resources with the ones provided by the spools
|
153 | 174 | * Given that they are allowed by app.config.main.resources
|
154 | 175 | */
|
155 |
| - mergeApi (app: FabrixApp, spool: Spool) { |
156 |
| - // Use the setter to see if any new api resources from the spool can be applied |
157 |
| - app.resources = union(app.resources, Object.keys(app.api), Object.keys(spool.api)) |
158 |
| - // Foreach resource, bind the spool.api into the app.api |
159 |
| - app.resources.forEach( resource => { |
160 |
| - // If there is a conflict, resolve it at the resource level |
161 |
| - if (app.api.hasOwnProperty(resource) && spool.api.hasOwnProperty(resource)) { |
162 |
| - Core.mergeApiResource(app, spool, resource) |
163 |
| - } |
164 |
| - // Else define the resource in the app.api and merge the spool.api resource into it |
165 |
| - else if (!app.api.hasOwnProperty(resource) && spool.api.hasOwnProperty(resource)) { |
166 |
| - app.api[resource] = {} |
167 |
| - Object.assign( |
168 |
| - (app.api[resource] || {}), |
169 |
| - (spool.api[resource] || {}) |
170 |
| - ) |
171 |
| - } |
| 176 | + mergeApi (app: FabrixApp) { |
| 177 | + const spools = Object.keys(app.spools).reverse() |
| 178 | + app.resources.forEach(resource => { |
| 179 | + spools.forEach(s => { |
| 180 | + // Add the defaults from the spools Apis |
| 181 | + defaultsDeep(app.api, app.spools[s].api) |
| 182 | + // Deep merge the Api |
| 183 | + Core.mergeApiResource(app, app.spools[s], resource) |
| 184 | + }) |
172 | 185 | })
|
173 | 186 | },
|
174 | 187 |
|
175 | 188 | /**
|
176 |
| - * Merge the Spool Api Resource if not already defined by App Api |
| 189 | + * Adds Api resources that were not merged by default |
177 | 190 | */
|
178 | 191 | mergeApiResource (app: FabrixApp, spool: Spool, resource: string) {
|
179 |
| - const spoolApiResources = Object.keys(spool.api[resource]) |
180 |
| - spoolApiResources.forEach(k => { |
181 |
| - if (!app.api[resource].hasOwnProperty(k)) { |
182 |
| - app.api[resource][k] = spool.api[resource][k] |
183 |
| - } |
| 192 | + if (app.api.hasOwnProperty(resource) && spool.api.hasOwnProperty(resource)) { |
| 193 | + Object.keys(spool.api[resource]).forEach(method => { |
| 194 | + Core.mergeApiResourceMethod(app, spool, resource, method) |
| 195 | + }) |
| 196 | + } |
| 197 | + }, |
| 198 | + |
| 199 | + /** |
| 200 | + * Adds Api resource methods that were not merged by default |
| 201 | + */ |
| 202 | + mergeApiResourceMethod (app: FabrixApp, spool: Spool, resource: string, method: string) { |
| 203 | + if (spool.api[resource].hasOwnProperty(method) && app.api[resource].hasOwnProperty(method)) { |
| 204 | + const spoolProto = Core.getPropertyNames(spool.api[resource][method]) |
| 205 | + spoolProto.forEach(proto => { |
| 206 | + if (!Core.hasPrototypeProperty(app.api[resource][method], proto)) { |
| 207 | + Core.mergePrototype(app.api[resource][method], spool.api[resource][method], proto) |
| 208 | + app.log.silly(`${spool.name}.api.${resource}.${method}.${proto} extending app.api.${resource}.${method}.${proto}`) |
| 209 | + } |
| 210 | + }) |
| 211 | + } |
| 212 | + }, |
| 213 | + |
| 214 | + /** |
| 215 | + * Merge the spool api resources with the ones provided by other spools |
| 216 | + * Given that they are allowed by app.config.main.resources |
| 217 | + */ |
| 218 | + mergeSpoolApi (app: FabrixApp, spool: Spool) { |
| 219 | + app.resources = union(app.resources, Object.keys(app.api), Object.keys(spool.api)) |
| 220 | + |
| 221 | + const spools = Object.keys(app.spools) |
| 222 | + .filter(s => s !== spool.name) |
| 223 | + |
| 224 | + app.resources.forEach(resource => { |
| 225 | + spools.forEach(s => { |
| 226 | + Core.mergeSpoolApiResource(app, app.spools[s], spool, resource) |
| 227 | + }) |
184 | 228 | })
|
185 | 229 | },
|
186 | 230 |
|
| 231 | + /** |
| 232 | + * Merge two Spools Api Resources's in order of their load |
| 233 | + */ |
| 234 | + mergeSpoolApiResource (app: FabrixApp, spool: Spool, next: Spool, resource: string) { |
| 235 | + if (spool.api.hasOwnProperty(resource) && next.api.hasOwnProperty(resource)) { |
| 236 | + Object.keys(next.api[resource]).forEach(method => { |
| 237 | + Core.mergeSpoolApiResourceMethod(app, spool, next, resource, method) |
| 238 | + }) |
| 239 | + } |
| 240 | + }, |
| 241 | + |
| 242 | + /** |
| 243 | + * Merge two Spools Api Resources Method's in order of their load |
| 244 | + */ |
| 245 | + mergeSpoolApiResourceMethod (app: FabrixApp, spool: Spool, next: Spool, resource: string, method: string) { |
| 246 | + if (spool.api[resource].hasOwnProperty(method) && next.api[resource].hasOwnProperty(method)) { |
| 247 | + const spoolProto = Core.getPropertyNames(spool.api[resource][method]) |
| 248 | + spoolProto.forEach(proto => { |
| 249 | + if (!Core.hasPrototypeProperty(next.api[resource][method], proto)) { |
| 250 | + Core.mergePrototype(next.api[resource][method], spool.api[resource][method], proto) |
| 251 | + app.log.silly(`${spool.name}.api.${resource}.${method}.${proto} extending ${next.name}.api.${resource}.${method}.${proto}`) |
| 252 | + } |
| 253 | + }) |
| 254 | + } |
| 255 | + }, |
| 256 | + |
187 | 257 | /**
|
188 | 258 | * Merge extensions provided by spools into the app
|
189 | 259 | */
|
|
0 commit comments