From e4a6d718bec0e9d249a4d26803b67e3c07c391fb Mon Sep 17 00:00:00 2001 From: Yuki von Kanel Date: Wed, 4 Jul 2018 14:21:34 -0500 Subject: [PATCH 1/5] Add experimental module merging support --- lib/loader.js | 8 +++++++ lib/main.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/lib/loader.js b/lib/loader.js index 39e8c32..eb04c0b 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -70,6 +70,11 @@ module.exports = { flatten: true, }) : {}; + // Add the target models path to our list of loaded model directories (so we can patch these later). @Poop. + if (!sails.barmecide.modelDirectories.includes(path)) { + sails.barmecide.modelDirectories.push(path); + } + // Transform the models so Sails is happy with them. const transformedModels = {}; Object.keys(models).forEach(modelName => { @@ -78,6 +83,9 @@ module.exports = { globalId: modelName, identity: ident, }); + + // Add a reference to the module, so we can replace this instance in addition to the later required copy. + sails.barmecide.modelModules.push({ identity: ident, module: models[modelName] }); }); // Merge in the transformed models. diff --git a/lib/main.js b/lib/main.js index 11156ba..0da9568 100644 --- a/lib/main.js +++ b/lib/main.js @@ -3,6 +3,7 @@ const path = require('path'); const loader = require('./loader'); const helpers = require('./helper'); const BarcemideHook = require('./hook'); +const includeAll = require('include-all'); const __hooks = require('sails/lib/hooks'); @@ -55,6 +56,8 @@ function initBarmecide(sails) { const barmecide = { hooksListing: [], activeHooks: [], + modelDirectories: [], + modelModules: [], rootPath: path.resolve(sails.config.paths.tmp, '..'), hookPath: sails.config.paths.hooks, findHook(identity) { @@ -102,14 +105,15 @@ function initBarmecide(sails) { sails.config.orm.moduleDefinitions = { models: {}, }; - // Load the main models using the Barmecide loader, so we won't wind up with partial definitions within - // hooks destroying the main definitions. - loader.loadModels(sails, sails.config.paths.models); // Finally, bind the barmecide object to the sails object. sails.barmecide = barmecide; sails.log.debug('[Barmecide]', 'Finished initializing! Hooks will now be loaded...'); + // Load the main models using the Barmecide loader, so we won't wind up with partial definitions within + // hooks destroying the main definitions. + loader.loadModels(sails, sails.config.paths.models); + // Start initializing the dependency hooks which Sails won't load by itself. dependencyHooks.forEach(hook => { const Shrek = __hooks(sails); @@ -120,4 +124,52 @@ function initBarmecide(sails) { sails.hooks[hook.name].identity = hook.name; sails.hooks[hook.name].configKey = hook.name; }); + + // Add an event handler for the ORM hook loading, so we can handle certain setup operations. + sails.on('hook:orm:loaded', () => { + // For each loaded model MODULE, we have to go through and patch them with the merged module, + // JUST IN CASE some weird code uses module.exports to access attribute definitions. + // + // Why so? Because unfortunately Sails modifies the module definitions, instead of generating + // a new object and leaving it alone. This causes attributes isIn, etc, to be removed, while + // processed values are placed under a `validations` object. + // + // Without this patching here, certain module.exports would have the validations replaced, while + // others might not, causing issues if the code just so happens to rely on this behaviour. + // + // Annoyingly, we have to rely on using model directories and a full new includeAll, in addition + // to simply storing a list of loaded model modules, as the module cache is invalidated. + // + barmecide.modelDirectories.forEach(path => { + const models = includeAll({ + dirname: path, + filter: /^(.+)\.(?:(?!md|txt).)+$/, + replaceExpr: /^.*\//, + flatten: true, + optional: true, + }); + + Object.keys(models).forEach(modelName => { + // Try and find the merged and loaded module definition. + const mergedModule = sails.config.orm.moduleDefinitions.models[modelName.toLowerCase()]; + // If we haven't found it, that's pretty freaky but we'll allow it, just skip. + if (!mergedModule) { + return; + } + // Pretty much replace the original module with the merged one. + Object.assign(models[modelName], mergedModule); + }); + }); + // We'll replace also the original modules just to be extra safe... + barmecide.modelModules.forEach(model => { + // Try and find the merged and loaded module definition. + const mergedModule = sails.config.orm.moduleDefinitions.models[model.identity]; + // If we haven't found it, that's pretty freaky but we'll allow it, just skip. + if (!mergedModule) { + return; + } + // Replace the original module with the merged one. + Object.assign(model.module, mergedModule); + }); + }); } From f7d92841cd2778293e7078c3a1fa4c7db2b8987d Mon Sep 17 00:00:00 2001 From: Yuki von Kanel Date: Wed, 4 Jul 2018 14:22:11 -0500 Subject: [PATCH 2/5] Bump to v0.0.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1698df0..9f1f68b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "barmecide", - "version": "0.0.3", + "version": "0.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6f966ea..3758773 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "barmecide", - "version": "0.0.3", + "version": "0.0.4", "description": "A castle of fog; a mirage; \"superpowers for your Sails.js hooks.\" This library provides a set of features from the (rightfully) discontinued marlinspike, while adding safety features and resolving issues with Sails v1.", "main": "lib/main.js", "scripts": { From fcee1671fa072a5a5b15b57d05484baba8dbdc00 Mon Sep 17 00:00:00 2001 From: Yuki von Kanel Date: Thu, 5 Jul 2018 11:54:55 -0500 Subject: [PATCH 3/5] Adjust config loading options --- lib/loader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/loader.js b/lib/loader.js index eb04c0b..14c56a1 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -8,6 +8,7 @@ module.exports = { loadConfig(path) { const config = fs.existsSync(path) && fs.statSync(path).isDirectory ? includeAll({ dirname: path, + filter: /^(.+).js$/, excludeDirs: /^env$/, recursive: true, flatten: true, From 9ae66ba49c3ba304547e436b04c06ebf6b070150 Mon Sep 17 00:00:00 2001 From: Yuki von Kanel Date: Thu, 5 Jul 2018 11:55:59 -0500 Subject: [PATCH 4/5] Add support for special bootstrap.js handling --- lib/hook.js | 59 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/lib/hook.js b/lib/hook.js index 74f7435..40308af 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -13,6 +13,7 @@ module.exports = class BarmecideHook { this.path = path.dirname(hookModule.filename); this.globalEntry = undefined; this.status = 'Loading'; + this.bootstrap = done => done(); // Setup some basic prefs object. this.prefs = { @@ -23,6 +24,7 @@ module.exports = class BarmecideHook { policies: true, config: true, }, + bootstrap: true, }; // Setup the hook resources object. @@ -104,31 +106,38 @@ module.exports = class BarmecideHook { return { initialize(done) { - // Run the underlying initialize method... - hook.initialize(err => { + // Run any bootstrap prior to registering. + hook.bootstrap(err => { // If an error was encountered, leave straight away. if (err) { return done(err); } - - // Otherwise, continue to register actions. - return this.registerActions(regErr => { - // If the action registration has failed, leave straight away with the error. - if (regErr) { - return done(regErr); - } - // Otherwise, we're completely done loading this hook, mark it as loaded! - hook.globalEntry.hasLoaded = true; - hook.status = 'OK'; - // Just in the event this was the last hook and we've now finished, output some summary info: - // TODO: move this to barmecide main - if (sails.barmecide.finishedLoading()) { - sails.log.info('[Barmecide]', 'All hooks finished loading!'); - sails.log.info('[Barmecide]', 'Loaded hooks summary:\n' + vanity.renderLoadInformation(sails.barmecide.activeHooks)); + // Run the underlying initialize method... + hook.initialize(err => { + // If an error was encountered, leave straight away. + if (err) { + return done(err); } - // Emit an event which can be listened for, signalling that the hook has been completely loaded. - sails.emit(`barmecide:hooks:${hook.globalEntry.name}:loaded`); - return done(); + + // Otherwise, continue to register actions. + return this.registerActions(regErr => { + // If the action registration has failed, leave straight away with the error. + if (regErr) { + return done(regErr); + } + // Otherwise, we're completely done loading this hook, mark it as loaded! + hook.globalEntry.hasLoaded = true; + hook.status = 'OK'; + // Just in the event this was the last hook and we've now finished, output some summary info: + // TODO: move this to barmecide main + if (sails.barmecide.finishedLoading()) { + sails.log.info('[Barmecide]', 'All hooks finished loading!'); + sails.log.info('[Barmecide]', 'Loaded hooks summary:\n' + vanity.renderLoadInformation(sails.barmecide.activeHooks)); + } + // Emit an event which can be listened for, signalling that the hook has been completely loaded. + sails.emit(`barmecide:hooks:${hook.globalEntry.name}:loaded`); + return done(); + }); }); }); }, @@ -215,6 +224,16 @@ module.exports = class BarmecideHook { hook.prefs.merge[key] = (barmecideConfig[key] !== false); }); + // Determine whether or not we should apply the special bootstrap merge behaviour or not. + hook.prefs.bootstrap = barmecideConfig.bootstrap !== false; + // If we've magic bootstrapping enabled, handle it. + if (hook.prefs.bootstrap) { + // If the bootstrap key is a proper function, use it as our handler, otherwise keep the default. + hook.bootstrap = (config.bootstrap instanceof Function) ? config.bootstrap : hook.bootstrap; + // Remove any bootstrap key from the config, so we don't run 2x. + delete config.bootstrap; + } + // Merge our configuration in, if desired. if (hook.prefs.merge.config) { _.defaultsDeep(sails.config, config); From 20960b75fae1f79da02ddc86a814083cbf1288b9 Mon Sep 17 00:00:00 2001 From: Yuki von Kanel Date: Thu, 5 Jul 2018 11:56:08 -0500 Subject: [PATCH 5/5] Bump to v0.0.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f1f68b..2463341 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "barmecide", - "version": "0.0.4", + "version": "0.0.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 3758773..28278b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "barmecide", - "version": "0.0.4", + "version": "0.0.5", "description": "A castle of fog; a mirage; \"superpowers for your Sails.js hooks.\" This library provides a set of features from the (rightfully) discontinued marlinspike, while adding safety features and resolving issues with Sails v1.", "main": "lib/main.js", "scripts": {