From b0e5a0bc633198958418a6c9d4fb318376c2ac36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Mon, 22 Feb 2016 11:01:06 +0100 Subject: [PATCH 01/10] executor: move "booted" and cb() to the next tick Fix executor to always emit the "booted" event and call the callback in the next tick of the event loop, regardless of whether there are any async boot scripts. Before this change, adding a listener for "booted" event was cumbersome: boot(app); if (app.booting) app.on('booted', handler); else handler(); With the fix in place, one can simply write the following: boot(app); app.on('booted', handler); --- lib/executor.js | 7 ++++++- test/executor.test.js | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/executor.js b/lib/executor.js index 3b7614c..c174212 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -43,7 +43,12 @@ module.exports = function execute(app, instructions, callback) { function(done) { enableAnonymousSwagger(app, instructions); done(); - }], function(err) { + }, + // Ensure both the "booted" event and the callback are always called + // in the next tick of the even loop. + // See http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony + process.nextTick, + ], function(err) { app.booting = false; if (err) return callback(err); diff --git a/test/executor.test.js b/test/executor.test.js index a6f716b..99ea363 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -66,15 +66,15 @@ describe('executor', function() { }); }); - it('should emit the `booted` event', function(done) { + it('should emit the `booted` event in the next tick', function(done) { + boot.execute(app, dummyInstructions, function(err) { + expect(err).to.be.undefined(); + }); app.on('booted', function() { // This test fails with a timeout when the `booted` event has not been // emitted correctly done(); }); - boot.execute(app, dummyInstructions, function(err) { - expect(err).to.be.undefined(); - }); }); it('should work when called synchronously', function() { From 058e0e2f56024f6e991709a156e4cf5fa2438862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Tue, 23 Feb 2016 12:08:30 +0100 Subject: [PATCH 02/10] 2.17.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * executor: move "booted" and cb() to the next tick (Miroslav Bajtoš) * Fix lodash 4.0.0 breaking changes (Jérémie Drouet) * When config is overriden with null don't merge (Farid Neshat) --- CHANGES.md | 14 ++++++++++---- package.json | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 61fe94d..c4b704d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,13 @@ +2016-02-23, Version 2.17.0 +========================== + + * executor: move "booted" and cb() to the next tick (Miroslav Bajtoš) + + * Fix lodash 4.0.0 breaking changes (Jérémie Drouet) + + * When config is overriden with null don't merge (Farid Neshat) + + 2015-12-22, Version 2.16.0 ========================== @@ -314,8 +324,6 @@ 2014-07-17, Version v2.0.0-beta3 ================================ - * v2.0.0-beta3 (Miroslav Bajtoš) - * compiler: return a clone of instructions (Miroslav Bajtoš) @@ -334,8 +342,6 @@ 2014-06-26, Version 2.0.0-beta1 =============================== - * 2.0.0-beta1 (Miroslav Bajtoš) - * test: fix jshint warnings (Miroslav Bajtoš) * compiler: fix references to loopback (Miroslav Bajtoš) diff --git a/package.json b/package.json index e266210..fc56cba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-boot", - "version": "2.16.0", + "version": "2.17.0", "description": "Convention-based bootstrapper for LoopBack applications", "keywords": [ "StrongLoop", From 902005ed8e9efb20ad3f56af1d09f20d83689319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Thu, 31 Mar 2016 13:29:39 +0200 Subject: [PATCH 03/10] Use eslint with loopback config Drop jshint and jscs in favour of eslint. --- .jshintignore => .eslintignore | 1 - .eslintrc | 3 + .jscsrc | 25 - .jshintrc | 21 - index.js | 2 +- lib/compiler.js | 34 +- lib/config-loader.js | 9 +- lib/executor.js | 16 +- package.json | 9 +- test/browser.multiapp.test.js | 12 +- test/browser.test.js | 6 +- test/compiler.test.js | 778 +++++++++--------- test/executor.test.js | 170 ++-- test/fixtures/browser-app-2/app.js | 2 +- .../browser-app/mixins/time-stamps.js | 2 - test/fixtures/passport.js | 2 +- test/fixtures/simple-component.js | 2 - test/helpers/appdir.js | 4 +- test/helpers/browser.js | 13 +- 19 files changed, 530 insertions(+), 581 deletions(-) rename .jshintignore => .eslintignore (63%) create mode 100644 .eslintrc delete mode 100644 .jscsrc delete mode 100644 .jshintrc diff --git a/.jshintignore b/.eslintignore similarity index 63% rename from .jshintignore rename to .eslintignore index d8f8557..1ede056 100644 --- a/.jshintignore +++ b/.eslintignore @@ -1,3 +1,2 @@ -node_modules/ coverage/ test/sandbox/ diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..70bcff8 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "loopback" +} diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index 6637ea4..0000000 --- a/.jscsrc +++ /dev/null @@ -1,25 +0,0 @@ -{ - "preset": "google", - "requireCurlyBraces": [ - "do", - "try", - "catch" - ], - "disallowMultipleVarDecl": "exceptUndefined", - "disallowSpacesInsideObjectBrackets": null, - "requireSpaceAfterLineComment": true, - "maximumLineLength": { - "value": 80, - "allowRegex": true - }, - "validateJSDoc": { - "checkParamNames": false, - "checkRedundantParams": false, - "requireParamTypes": true - }, - "excludeFiles": [ - "node_modules/**", - "coverage/**", - "test/sandbox/**" - ] -} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 6f9fcc5..0000000 --- a/.jshintrc +++ /dev/null @@ -1,21 +0,0 @@ -{ -"node": true, -"browser": true, -"eqnull" : true, -"indent": 2, -"undef": true, -"unused": true, -"quotmark": "single", -"newcap": true, -"nonew": true, -"sub": true, -"unused": "vars", -"globals": { - "describe": false, - "it": false, - "before": false, - "beforeEach": false, - "after": false, - "afterEach": false -} -} diff --git a/index.js b/index.js index e8a4ad7..4619e51 100644 --- a/index.js +++ b/index.js @@ -154,7 +154,7 @@ exports.compileToBrowserify = function(options, bundler) { addInstructionsToBrowserify(compile(options), bundler); }; -/*-- undocumented low-level API --*/ +/* -- undocumented low-level API -- */ exports.ConfigLoader = ConfigLoader; exports.compile = compile; diff --git a/lib/compiler.js b/lib/compiler.js index 43661cf..d9fee0f 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -103,8 +103,8 @@ module.exports = function compile(options) { components: componentInstructions, mixins: mixinInstructions, files: { - boot: bootScripts - } + boot: bootScripts, + }, }; if (options.appId) @@ -215,7 +215,7 @@ function buildAllModelInstructions(rootDir, modelsConfig, sources, name: name, config: config, definition: definition.definition, - sourceFile: definition.sourceFile + sourceFile: definition.sourceFile, }; }); @@ -415,7 +415,6 @@ function tryResolveAppPath(rootDir, relativePath, resolveOptions) { try { // NOTE(bajtos) We need to create a proper String object here, // otherwise we can't attach additional properties to it - /*jshint -W053 */ var filePath = new String(require.resolve(absPath)); filePath.unresolvedPath = absPath; return filePath; @@ -457,7 +456,7 @@ function loadModelDefinition(rootDir, jsonFile, allFiles) { return { definition: definition, - sourceFile: sourceFile + sourceFile: sourceFile, }; } @@ -495,7 +494,7 @@ function buildMiddlewareInstructions(rootDir, config) { var item = { sourceFile: resolved.sourceFile, - config: middlewareConfig + config: middlewareConfig, }; if (resolved.fragment) { item.fragment = resolved.fragment; @@ -517,13 +516,13 @@ function buildMiddlewareInstructions(rootDir, config) { return { phases: flattenedPhaseNames, - middleware: middlewareList + middleware: middlewareList, }; } function resolveMiddlewarePath(rootDir, middleware, config) { var resolved = { - optional: !!config.optional + optional: !!config.optional, }; var segments = middleware.split('#'); @@ -532,7 +531,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) { var middlewarePath = pathName; var opts = { strict: true, - optional: !!config.optional + optional: !!config.optional, }; if (fragment) { @@ -552,7 +551,7 @@ function resolveMiddlewarePath(rootDir, middleware, config) { // node_modules/strong-express-metrics // instead of // node_modules/strong-express-metrics/index.js - fullResolve: false + fullResolve: false, }); var sourceFile = resolveAppScriptPath(rootDir, middlewarePath, resolveOpts); @@ -581,14 +580,13 @@ function resolveMiddlewarePath(rootDir, middleware, config) { // pathName + '/' + fragment ]; - var err; + var err = undefined; // see https://github.com/eslint/eslint/issues/5744 for (var ix in candidates) { try { resolved.sourceFile = resolveAppScriptPath(rootDir, candidates[ix], opts); delete resolved.fragment; return resolved; - } - catch (e) { + } catch (e) { // Report the error for the first candidate when no candidate matches if (!err) err = e; } @@ -615,7 +613,7 @@ function buildComponentInstructions(rootDir, componentConfig) { .map(function(name) { return { sourceFile: resolveAppScriptPath(rootDir, name, { strict: true }), - config: componentConfig[name] + config: componentConfig[name], }; }); } @@ -635,11 +633,11 @@ function resolveRelativePaths(relativePaths, appRootDir) { function getExcludedExtensions() { return { '.json': '.json', - '.node': 'node' + '.node': 'node', }; } -function isPreferredExtension (filename) { +function isPreferredExtension(filename) { var includeExtensions = require.extensions; var ext = path.extname(filename); @@ -793,7 +791,9 @@ function normalizeMixinName(str, options) { case 'classify': str = String(str).replace(/([A-Z]+)/g, ' $1').trim(); str = String(str).replace(/[\W_]/g, ' ').toLowerCase(); - str = str.replace(/(?:^|\s|-)\S/g, function(c) { return c.toUpperCase(); }); + str = str.replace(/(?:^|\s|-)\S/g, function(c) { + return c.toUpperCase(); + }); str = str.replace(/\s+/g, ''); return str; diff --git a/lib/config-loader.js b/lib/config-loader.js index c2baf32..3f2a5fc 100644 --- a/lib/config-loader.js +++ b/lib/config-loader.js @@ -32,7 +32,6 @@ ConfigLoader.loadDataSources = function(rootDir, env) { * @returns {Object} */ ConfigLoader.loadModels = function(rootDir, env) { - /*jshint unused:false */ return loadNamed(rootDir, env, 'model-config', mergeModelConfig); }; @@ -98,7 +97,7 @@ function findConfigFiles(appRootDir, env, name) { var candidates = [ master, ifExistsWithAnyExt(name + '.local'), - ifExistsWithAnyExt(name + '.' + env) + ifExistsWithAnyExt(name + '.' + env), ]; return candidates.filter(function(c) { return c !== undefined; }); @@ -124,7 +123,7 @@ function loadConfigFiles(files) { var config = require(f); Object.defineProperty(config, '_filename', { enumerable: false, - value: f + value: f, }); return config; }); @@ -166,7 +165,7 @@ function mergeAppConfig(target, config, fileName) { } function mergeMiddlewareConfig(target, config, fileName) { - var err; + var err = undefined; // see https://github.com/eslint/eslint/issues/5744 for (var phase in config) { if (phase in target) { err = mergePhaseConfig(target[phase], config[phase], phase); @@ -203,7 +202,7 @@ function mergeNamedItems(arr1, arr2, key) { } function mergePhaseConfig(target, config, phase) { - var err; + var err = undefined; // see https://github.com/eslint/eslint/issues/5744 for (var mw in config) { if (mw in target) { var targetMiddleware = target[mw]; diff --git a/lib/executor.js b/lib/executor.js index c174212..dfc7379 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -48,15 +48,15 @@ module.exports = function execute(app, instructions, callback) { // in the next tick of the even loop. // See http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony process.nextTick, - ], function(err) { - app.booting = false; + ], function(err) { + app.booting = false; - if (err) return callback(err); + if (err) return callback(err); - app.emit('booted'); + app.emit('booted'); - callback(); - }); + callback(); + }); }; function patchAppLoopback(app) { @@ -128,7 +128,7 @@ function setPort(app, instructions) { instructions.config.port, process.env.npm_package_config_port, app.get('port'), - 3000 + 3000, ], function(p) { return p != null; }); @@ -277,7 +277,7 @@ function runScripts(app, list, callback) { debug('Exported function detected %s', filepath); functions.push({ path: filepath, - func: exports + func: exports, }); } } catch (err) { diff --git a/package.json b/package.json index fc56cba..bbc4711 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,9 @@ "main": "index.js", "browser": "browser.js", "scripts": { - "pretest": "jscs . && jshint .", - "test": "mocha" + "test": "mocha", + "posttest": "npm run lint", + "lint": "eslint ." }, "license": "MIT", "dependencies": { @@ -32,9 +33,9 @@ "chai": "^1.10.0", "coffee-script": "^1.8.0", "coffeeify": "^0.7.0", + "eslint": "^2.5.3", + "eslint-config-loopback": "^1.0.0", "fs-extra": "^0.12.0", - "jscs": "^1.7.3", - "jshint": "^2.5.6", "loopback": "^2.16.3", "mocha": "^1.19.0", "supertest": "^0.14.0" diff --git a/test/browser.multiapp.test.js b/test/browser.multiapp.test.js index e0a256d..759a9ed 100644 --- a/test/browser.multiapp.test.js +++ b/test/browser.multiapp.test.js @@ -22,14 +22,14 @@ describe('browser support for multiple apps', function() { { appDir: app1Dir, appFile: './app.js', - moduleName: 'browser-app' + moduleName: 'browser-app', }, { appDir: app2Dir, appFile: './app.js', moduleName: 'browser-app2', - appId: 'browserApp2' - } + appId: 'browserApp2', + }, ]; browserifyTestApps(apps, function(err, bundlePath) { @@ -55,7 +55,7 @@ describe('browser support for multiple apps', function() { function browserifyTestApps(apps, next) { var b = browserify({ - debug: true + debug: true, }); for (var i in apps) { @@ -65,13 +65,13 @@ function browserifyTestApps(apps, next) { var appId = apps[i].appId; appFile = path.join(appDir, appFile); - b.require(appFile, {expose: moduleName}); + b.require(appFile, { expose: moduleName }); var opts = appDir; if (appId) { opts = { appId: appId, - appRootDir: appDir + appRootDir: appDir, }; } boot.compileToBrowserify(opts, b); diff --git a/test/browser.test.js b/test/browser.test.js index 44e0b7a..753fcd9 100644 --- a/test/browser.test.js +++ b/test/browser.test.js @@ -13,7 +13,7 @@ var compileStrategies = { 'default': function(appDir) { var b = browserify({ basedir: appDir, - debug: true + debug: true, }); b.require('./app.js', { expose: 'browser-app' }); @@ -24,7 +24,7 @@ var compileStrategies = { var b = browserify({ basedir: appDir, extensions: ['.coffee'], - debug: true + debug: true, }); b.transform('coffeeify'); @@ -64,7 +64,7 @@ describe('browser support', function() { it('loads mixins', function(done) { var appDir = path.resolve(__dirname, './fixtures/browser-app'); var options = { - appRootDir: appDir + appRootDir: appDir, }; browserifyTestApp(options, function(err, bundlePath) { diff --git a/test/compiler.test.js b/test/compiler.test.js index ee34e0e..eac294f 100644 --- a/test/compiler.test.js +++ b/test/compiler.test.js @@ -15,9 +15,7 @@ describe('compiler', function() { beforeEach(appdir.init); describe('from options', function() { - var options; - var instructions; - var appConfig; + var options, instructions, appConfig; beforeEach(function() { options = { @@ -25,20 +23,20 @@ describe('compiler', function() { port: 3000, host: '127.0.0.1', restApiRoot: '/rest-api', - foo: {bar: 'bat'}, - baz: true + foo: { bar: 'bat' }, + baz: true, }, models: { 'foo-bar-bat-baz': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, dataSources: { 'the-db': { connector: 'memory', - defaultForType: 'db' - } - } + defaultForType: 'db', + }, + }, }; instructions = boot.compile(options); appConfig = instructions.config; @@ -59,7 +57,7 @@ describe('compiler', function() { it('has other settings', function() { expect(appConfig).to.have.property('baz', true); expect(appConfig.foo, 'appConfig.foo').to.eql({ - bar: 'bat' + bar: 'bat', }); }); @@ -68,10 +66,10 @@ describe('compiler', function() { expect(instructions.models[0]).to.eql({ name: 'foo-bar-bat-baz', config: { - dataSource: 'the-db' + dataSource: 'the-db', }, definition: undefined, - sourceFile: undefined + sourceFile: undefined, }); }); @@ -81,7 +79,7 @@ describe('compiler', function() { describe('with custom model definitions', function() { var dataSources = { - 'the-db': { connector: 'memory' } + 'the-db': { connector: 'memory' }, }; it('loads model without definition', function() { @@ -89,11 +87,11 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'model-without-definition': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name) .to.equal('model-without-definition'); @@ -108,23 +106,23 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'coffee-model-with-definition': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [ { definition: { - name: 'coffee-model-with-definition' + name: 'coffee-model-with-definition', }, - sourceFile: modelScript - } + sourceFile: modelScript, + }, ], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name) .to.equal('coffee-model-with-definition'); expect(instruction.models[0].definition).to.eql({ - name: 'coffee-model-with-definition' + name: 'coffee-model-with-definition', }); expect(instruction.models[0].sourceFile).to.equal(modelScript); }); @@ -137,16 +135,16 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'model-without-ext': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [{ definition: { - name: 'model-without-ext' + name: 'model-without-ext', }, - sourceFile: pathWithoutExtension(modelScript) + sourceFile: pathWithoutExtension(modelScript), }], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name).to.equal('model-without-ext'); expect(instruction.models[0].sourceFile).to.equal(modelScript); @@ -160,16 +158,16 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'model-without-ext': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [{ definition: { - name: 'model-without-ext' + name: 'model-without-ext', }, - sourceFile: pathWithoutExtension(modelScript) + sourceFile: pathWithoutExtension(modelScript), }], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name).to.equal('model-without-ext'); expect(instruction.models[0].sourceFile).to.equal(modelScript); @@ -183,18 +181,18 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'model-with-definition': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [ { definition: { - name: 'model-with-definition' + name: 'model-with-definition', }, - sourceFile: modelScript - } + sourceFile: modelScript, + }, ], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name).to.equal('model-with-definition'); expect(instruction.models[0].definition).not.to.equal(undefined); @@ -207,19 +205,19 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'model-with-definition-with-falsey-source-file': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [ { definition: { - name: 'model-with-definition-with-falsey-source-file' + name: 'model-with-definition-with-falsey-source-file', }, sourceFile: appdir.resolve('custom-models', - 'file-does-not-exist.js') - } + 'file-does-not-exist.js'), + }, ], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name) .to.equal('model-with-definition-with-falsey-source-file'); @@ -233,18 +231,18 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'model-with-definition-without-source-file-property': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [ { definition: { - name: 'model-with-definition-without-source-file-property' - } + name: 'model-with-definition-without-source-file-property', + }, // sourceFile is not set - } + }, ], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models[0].name) .to.equal('model-with-definition-without-source-file-property'); @@ -257,22 +255,22 @@ describe('compiler', function() { appRootDir: appdir.PATH, models: { 'some-model': { - dataSource: 'the-db' - } + dataSource: 'the-db', + }, }, modelDefinitions: [ { definition: { - name: 'some-model' - } + name: 'some-model', + }, }, { definition: { - name: 'another-model' - } - } + name: 'another-model', + }, + }, ], - dataSources: dataSources + dataSources: dataSources, }); expect(instruction.models.map(getNameProperty)) @@ -289,22 +287,22 @@ describe('compiler', function() { expect(instructions.models[0]).to.eql({ name: 'User', config: { - dataSource: 'db' + dataSource: 'db', }, definition: undefined, - sourceFile: undefined + sourceFile: undefined, }); }); it('merges datasource configs from multiple files', function() { appdir.createConfigFilesSync(); appdir.writeConfigFileSync('datasources.local.json', { - db: { local: 'applied' } + db: { local: 'applied' }, }); var env = process.env.NODE_ENV || 'development'; appdir.writeConfigFileSync('datasources.' + env + '.json', { - db: { env: 'applied' } + db: { env: 'applied' }, }); var instructions = boot.compile(appdir.PATH); @@ -336,7 +334,7 @@ describe('compiler', function() { var objectValue = { key: 'value' }; appdir.createConfigFilesSync(); appdir.writeConfigFileSync('datasources.local.json', { - db: { nested: objectValue } + db: { nested: objectValue }, }); var instructions = boot.compile(appdir.PATH); @@ -350,17 +348,17 @@ describe('compiler', function() { appdir.createConfigFilesSync({}, { email: { transport: { - host: 'localhost' - } - } + host: 'localhost', + }, + }, }); appdir.writeConfigFileSync('datasources.local.json', { email: { transport: { - host: 'mail.example.com' - } - } + host: 'mail.example.com', + }, + }, }); var instructions = boot.compile(appdir.PATH); @@ -375,11 +373,11 @@ describe('compiler', function() { { template: { method: 'POST', - url: 'http://localhost:12345' - } - } - ] - } + url: 'http://localhost:12345', + }, + }, + ], + }, }); appdir.writeConfigFileSync('datasources.local.json', { @@ -387,11 +385,11 @@ describe('compiler', function() { operations: [ { template: { - url: 'http://api.example.com' - } - } - ] - } + url: 'http://api.example.com', + }, + }, + ], + }, }); var instructions = boot.compile(appdir.PATH); @@ -399,7 +397,7 @@ describe('compiler', function() { var rest = instructions.dataSources.rest; expect(rest.operations[0].template).to.eql({ method: 'POST', // the value from datasources.json - url: 'http://api.example.com' // overriden in datasources.local.json + url: 'http://api.example.com', // overriden in datasources.local.json }); }); @@ -407,7 +405,7 @@ describe('compiler', function() { var arrayValue = ['value']; appdir.createConfigFilesSync(); appdir.writeConfigFileSync('datasources.local.json', { - db: { nested: arrayValue } + db: { nested: arrayValue }, }); var instructions = boot.compile(appdir.PATH); @@ -420,7 +418,7 @@ describe('compiler', function() { it('allows env specific model-config json', function() { appdir.createConfigFilesSync(); appdir.writeConfigFileSync('model-config.local.json', { - foo: { dataSource: 'db' } + foo: { dataSource: 'db' }, }); var instructions = boot.compile(appdir.PATH); @@ -431,9 +429,9 @@ describe('compiler', function() { it('allows env specific model-config json to be merged', function() { appdir.createConfigFilesSync(null, null, - {foo: {dataSource: 'mongo', public: false}}); + { foo: { dataSource: 'mongo', public: false }}); appdir.writeConfigFileSync('model-config.local.json', { - foo: {dataSource: 'db'} + foo: { dataSource: 'db' }, }); var instructions = boot.compile(appdir.PATH); @@ -442,7 +440,7 @@ describe('compiler', function() { expect(instructions.models[0]).to.have.property('name', 'foo'); expect(instructions.models[0].config).to.eql({ dataSource: 'db', - public: false + public: false, }); }); @@ -460,18 +458,18 @@ describe('compiler', function() { it('refuses to merge Array properties of different length', function() { appdir.createConfigFilesSync({ nest: { - array: [] - } + array: [], + }, }); appdir.writeConfigFileSync('config.local.json', { nest: { array: [ { - key: 'value' - } - ] - } + key: 'value', + }, + ], + }, }); expect(function() { boot.compile(appdir.PATH); }) @@ -480,11 +478,11 @@ describe('compiler', function() { it('refuses to merge Array of different length in Array', function() { appdir.createConfigFilesSync({ - key: [[]] + key: [[]], }); appdir.writeConfigFileSync('config.local.json', { - key: [['value']] + key: [['value']], }); expect(function() { boot.compile(appdir.PATH); }) @@ -495,17 +493,17 @@ describe('compiler', function() { appdir.createConfigFilesSync({ toplevel: [ { - nested: [] - } - ] + nested: [], + }, + ], }); appdir.writeConfigFileSync('config.local.json', { toplevel: [ { - nested: ['value'] - } - ] + nested: ['value'], + }, + ], }); expect(function() { boot.compile(appdir.PATH); }) @@ -514,10 +512,10 @@ describe('compiler', function() { it('refuses to merge incompatible object properties', function() { appdir.createConfigFilesSync({ - key: [] + key: [], }); appdir.writeConfigFileSync('config.local.json', { - key: {} + key: {}, }); expect(function() { boot.compile(appdir.PATH); }) @@ -526,10 +524,10 @@ describe('compiler', function() { it('refuses to merge incompatible array items', function() { appdir.createConfigFilesSync({ - key: [[]] + key: [[]], }); appdir.writeConfigFileSync('config.local.json', { - key: [{}] + key: [{}], }); expect(function() { boot.compile(appdir.PATH); }) @@ -571,7 +569,7 @@ describe('compiler', function() { }); it('supports `appConfigRootDir` option', function() { - appdir.createConfigFilesSync({port:3000}); + appdir.createConfigFilesSync({ port: 3000 }); var customDir = path.resolve(appdir.PATH, 'custom'); fs.mkdirsSync(customDir); @@ -581,7 +579,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - appConfigRootDir: path.resolve(appdir.PATH, 'custom') + appConfigRootDir: path.resolve(appdir.PATH, 'custom'), }); expect(instructions.config).to.have.property('port'); @@ -598,7 +596,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - dsRootDir: path.resolve(appdir.PATH, 'custom') + dsRootDir: path.resolve(appdir.PATH, 'custom'), }); expect(instructions.dataSources).to.have.property('db'); @@ -607,12 +605,12 @@ describe('compiler', function() { it('supports `modelsRootDir` option', function() { appdir.createConfigFilesSync(); appdir.writeConfigFileSync('custom/model-config.json', { - foo: { dataSource: 'db' } + foo: { dataSource: 'db' }, }); var instructions = boot.compile({ appRootDir: appdir.PATH, - modelsRootDir: path.resolve(appdir.PATH, 'custom') + modelsRootDir: path.resolve(appdir.PATH, 'custom'), }); expect(instructions.models).to.have.length(1); @@ -633,7 +631,7 @@ describe('compiler', function() { 'module.exports = function(app) { app.fnCalled = true; };'); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs: [path.dirname(initJs)] + bootDirs: [path.dirname(initJs)], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -644,7 +642,7 @@ describe('compiler', function() { 'module.exports = function(app) { app.fnCalled = true; };'); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs:['./custom-boot'] + bootDirs: ['./custom-boot'], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -654,7 +652,7 @@ describe('compiler', function() { var initJs = appdir.writeFileSync('custom-boot/init.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs:['custom-boot'] + bootDirs: ['custom-boot'], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -664,7 +662,7 @@ describe('compiler', function() { appdir.writeFileSync('custom-boot/index.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs:['./custom-boot'] + bootDirs: ['./custom-boot'], }); expect(instructions.files.boot).to.have.length(0); }); @@ -676,13 +674,13 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs: ['./custom-boot'] + bootDirs: ['./custom-boot'], }); expect(instructions.files.boot).to.eql([coffee]); }); it('prefers coffeescript over json in `bootDir` non-relative path', - function() { + function() { appdir.createConfigFilesSync(); var coffee = appdir.writeFileSync('custom-boot/init.coffee', ''); @@ -690,7 +688,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs: ['custom-boot'] + bootDirs: ['custom-boot'], }); expect(instructions.files.boot).to.eql([coffee]); }); @@ -701,7 +699,7 @@ describe('compiler', function() { 'module.exports = function(app) { app.fnCalled = true; };'); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts: [initJs] + bootScripts: [initJs], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -712,8 +710,8 @@ describe('compiler', function() { 'module.exports = function(app) { app.fnCalled = true; };'); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootDirs:[path.dirname(initJs)], - bootScripts: [initJs] + bootDirs: [path.dirname(initJs)], + bootScripts: [initJs], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -724,7 +722,7 @@ describe('compiler', function() { 'module.exports = function(app) { app.fnCalled = true; };'); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts: ['./custom-boot/init.js'] + bootScripts: ['./custom-boot/init.js'], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -734,7 +732,7 @@ describe('compiler', function() { var initJs = appdir.writeFileSync('custom-boot/init.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts: ['custom-boot/init.js'] + bootScripts: ['custom-boot/init.js'], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -744,19 +742,19 @@ describe('compiler', function() { var initJs = appdir.writeFileSync('custom-boot/init.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts:['./custom-boot/init'] + bootScripts: ['./custom-boot/init'], }); expect(instructions.files.boot).to.eql([initJs]); }); it('resolves missing extensions in `bootScripts` in module relative path', - function() { + function() { appdir.createConfigFilesSync(); var initJs = appdir.writeFileSync('node_modules/custom-boot/init.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts: ['custom-boot/init'] + bootScripts: ['custom-boot/init'], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -766,7 +764,7 @@ describe('compiler', function() { var initJs = appdir.writeFileSync('node_modules/custom-boot/init.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts: ['custom-boot/init.js'] + bootScripts: ['custom-boot/init.js'], }); expect(instructions.files.boot).to.eql([initJs]); }); @@ -779,7 +777,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - bootScripts: ['custom-boot/init.js'] + bootScripts: ['custom-boot/init.js'], }); expect(instructions.files.boot).to.eql([appJs]); }); @@ -795,7 +793,7 @@ describe('compiler', function() { it('throws when models-config.json contains 1.x `properties`', function() { appdir.createConfigFilesSync({}, {}, { - foo: { properties: { name: 'string' } } + foo: { properties: { name: 'string' }}, }); expect(function() { boot.compile(appdir.PATH); }) @@ -804,7 +802,7 @@ describe('compiler', function() { it('throws when model-config.json contains 1.x `options.base`', function() { appdir.createConfigFilesSync({}, {}, { - Customer: { options: { base: 'User' } } + Customer: { options: { base: 'User' }}, }); expect(function() { boot.compile(appdir.PATH); }) @@ -813,7 +811,7 @@ describe('compiler', function() { it('loads models from `./models`', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car' }); appdir.writeFileSync('models/car.js', ''); @@ -824,18 +822,18 @@ describe('compiler', function() { expect(instructions.models[0]).to.eql({ name: 'Car', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { - name: 'Car' + name: 'Car', }, - sourceFile: path.resolve(appdir.PATH, 'models', 'car.js') + sourceFile: path.resolve(appdir.PATH, 'models', 'car.js'), }); }); it('loads coffeescript models from `./models`', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car' }); appdir.writeFileSync('models/car.coffee', ''); @@ -846,46 +844,46 @@ describe('compiler', function() { expect(instructions.models[0]).to.eql({ name: 'Car', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { - name: 'Car' + name: 'Car', }, - sourceFile: path.resolve(appdir.PATH, 'models', 'car.coffee') + sourceFile: path.resolve(appdir.PATH, 'models', 'car.coffee'), }); }); it('supports `modelSources` option', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('custom-models/car.json', { name: 'Car' }); appdir.writeFileSync('custom-models/car.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - modelSources: ['./custom-models'] + modelSources: ['./custom-models'], }); expect(instructions.models).to.have.length(1); expect(instructions.models[0]).to.eql({ name: 'Car', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { - name: 'Car' + name: 'Car', }, - sourceFile: path.resolve(appdir.PATH, 'custom-models', 'car.js') + sourceFile: path.resolve(appdir.PATH, 'custom-models', 'car.js'), }); }); it('supports `sources` option in `model-config.json`', function() { appdir.createConfigFilesSync({}, {}, { _meta: { - sources: ['./custom-models'] + sources: ['./custom-models'], }, - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('custom-models/car.json', { name: 'Car' }); appdir.writeFileSync('custom-models/car.js', ''); @@ -896,49 +894,49 @@ describe('compiler', function() { expect(instructions.models[0]).to.eql({ name: 'Car', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { - name: 'Car' + name: 'Car', }, - sourceFile: path.resolve(appdir.PATH, 'custom-models', 'car.js') + sourceFile: path.resolve(appdir.PATH, 'custom-models', 'car.js'), }); }); it('supports sources relative to node_modules', function() { appdir.createConfigFilesSync({}, {}, { - User: { dataSource: 'db' } + User: { dataSource: 'db' }, }); var instructions = boot.compile({ appRootDir: appdir.PATH, modelSources: [ 'loopback/common/models', - 'loopback/common/dir-does-not-exist' - ] + 'loopback/common/dir-does-not-exist', + ], }); expect(instructions.models).to.have.length(1); expect(instructions.models[0]).to.eql({ name: 'User', config: { - dataSource: 'db' + dataSource: 'db', }, definition: require('loopback/common/models/user.json'), - sourceFile: require.resolve('loopback/common/models/user.js') + sourceFile: require.resolve('loopback/common/models/user.js'), }); }); it('resolves relative path in `modelSources` option', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('custom-models/car.json', { name: 'Car' }); var appJS = appdir.writeFileSync('custom-models/car.js', ''); var instructions = boot.compile({ appRootDir: appdir.PATH, - modelSources: ['./custom-models'] + modelSources: ['./custom-models'], }); expect(instructions.models).to.have.length(1); @@ -947,7 +945,7 @@ describe('compiler', function() { it('resolves module relative path in `modelSources` option', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('node_modules/custom-models/car.json', { name: 'Car' }); @@ -955,7 +953,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - modelSources: ['custom-models'] + modelSources: ['custom-models'], }); expect(instructions.models).to.have.length(1); @@ -963,12 +961,12 @@ describe('compiler', function() { }); it('resolves relative path in `sources` option in `model-config.json`', - function() { + function() { appdir.createConfigFilesSync({}, {}, { _meta: { - sources: ['./custom-models'] + sources: ['./custom-models'], }, - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('custom-models/car.json', { name: 'Car' }); var appJS = appdir.writeFileSync('custom-models/car.js', ''); @@ -980,12 +978,12 @@ describe('compiler', function() { }); it('resolves module relative path in `sources` option in model-config.json', - function() { + function() { appdir.createConfigFilesSync({}, {}, { _meta: { - sources: ['custom-models'] + sources: ['custom-models'], }, - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('node_modules/custom-models/car.json', { name: 'Car' }); @@ -1000,7 +998,7 @@ describe('compiler', function() { it('handles model definitions with no code', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car' }); @@ -1009,18 +1007,18 @@ describe('compiler', function() { expect(instructions.models).to.eql([{ name: 'Car', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { - name: 'Car' + name: 'Car', }, - sourceFile: undefined + sourceFile: undefined, }]); }); it('excludes models not listed in `model-config.json`', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car' }); appdir.writeConfigFileSync('models/bar.json', { name: 'Bar' }); @@ -1033,14 +1031,14 @@ describe('compiler', function() { it('includes models used as Base models', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car', - base: 'Vehicle' + base: 'Vehicle', }); appdir.writeConfigFileSync('models/vehicle.json', { - name: 'Vehicle' + name: 'Vehicle', }); var instructions = boot.compile(appdir.PATH); @@ -1053,11 +1051,11 @@ describe('compiler', function() { it('excludes pre-built base models', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car', - base: 'Model' + base: 'Model', }); var instructions = boot.compile(appdir.PATH); @@ -1070,18 +1068,18 @@ describe('compiler', function() { appdir.createConfigFilesSync({}, {}, { Vehicle: { dataSource: 'db' }, FlyingCar: { dataSource: 'db' }, - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car', - base: 'Vehicle' + base: 'Vehicle', }); appdir.writeConfigFileSync('models/vehicle.json', { - name: 'Vehicle' + name: 'Vehicle', }); appdir.writeConfigFileSync('models/flying-car.json', { name: 'FlyingCar', - base: 'Car' + base: 'Car', }); var instructions = boot.compile(appdir.PATH); @@ -1093,15 +1091,15 @@ describe('compiler', function() { it('detects circular Model dependencies', function() { appdir.createConfigFilesSync({}, {}, { Vehicle: { dataSource: 'db' }, - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car', - base: 'Vehicle' + base: 'Vehicle', }); appdir.writeConfigFileSync('models/vehicle.json', { name: 'Vehicle', - base: 'Car' + base: 'Car', }); expect(function() { boot.compile(appdir.PATH); }) @@ -1110,7 +1108,7 @@ describe('compiler', function() { it('uses file name as default value for model name', function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', {}); @@ -1121,9 +1119,9 @@ describe('compiler', function() { }); it('uses `OrderItem` as default model name for file with name `order-item`', - function() { + function() { appdir.createConfigFilesSync({}, {}, { - OrderItem: { dataSource: 'db' } + OrderItem: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/order-item.json', {}); @@ -1134,9 +1132,9 @@ describe('compiler', function() { }); it('uses `OrderItem` as default model name for file with name `order_item`', - function() { + function() { appdir.createConfigFilesSync({}, {}, { - OrderItem: { dataSource: 'db' } + OrderItem: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/order_item.json', {}); @@ -1147,9 +1145,9 @@ describe('compiler', function() { }); it('uses `OrderItem` as default model name for file with name `order item`', - function() { + function() { appdir.createConfigFilesSync({}, {}, { - OrderItem: { dataSource: 'db' } + OrderItem: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/order item.json', {}); @@ -1160,11 +1158,11 @@ describe('compiler', function() { }); it('overrides `default model name` by `name` in model definition', - function() { + function() { appdir.createConfigFilesSync({}, {}, { - overrideCar: { dataSource: 'db' } + overrideCar: { dataSource: 'db' }, }); - appdir.writeConfigFileSync('models/car.json', { name: 'overrideCar'}); + appdir.writeConfigFileSync('models/car.json', { name: 'overrideCar' }); var instructions = boot.compile(appdir.PATH); @@ -1174,20 +1172,20 @@ describe('compiler', function() { it('overwrites model with same default name', function() { appdir.createConfigFilesSync({}, {}, { - 'OrderItem': { dataSource: 'db' } + 'OrderItem': { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/order-item.json', { properties: { - price: { type: 'number' } - } + price: { type: 'number' }, + }, }); appdir.writeFileSync('models/order-item.js', ''); appdir.writeConfigFileSync('models/orderItem.json', { properties: { - quantity: { type: 'number' } - } + quantity: { type: 'number' }, + }, }); var appJS = appdir.writeFileSync('models/orderItem.js', ''); @@ -1196,36 +1194,36 @@ describe('compiler', function() { expect(instructions.models).to.eql([{ name: 'OrderItem', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { name: 'OrderItem', properties: { - quantity: {type: 'number'} - } + quantity: { type: 'number' }, + }, }, - sourceFile: appJS + sourceFile: appJS, }]); }); it('overwrites model with same name in model definition', function() { appdir.createConfigFilesSync({}, {}, { - 'customOrder': { dataSource: 'db' } + 'customOrder': { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/order1.json', { - name : 'customOrder', + name: 'customOrder', properties: { - price: { type: 'number' } - } + price: { type: 'number' }, + }, }); appdir.writeFileSync('models/order1.js', ''); appdir.writeConfigFileSync('models/order2.json', { - name : 'customOrder', + name: 'customOrder', properties: { - quantity: { type: 'number' } - } + quantity: { type: 'number' }, + }, }); var appJS = appdir.writeFileSync('models/order2.js', ''); @@ -1234,15 +1232,15 @@ describe('compiler', function() { expect(instructions.models).to.eql([{ name: 'customOrder', config: { - dataSource: 'db' + dataSource: 'db', }, definition: { name: 'customOrder', properties: { - quantity: {type: 'number'} - } + quantity: { type: 'number' }, + }, }, - sourceFile: appJS + sourceFile: appJS, }]); }); @@ -1263,7 +1261,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - mixinDirs: mixinDirs + mixinDirs: mixinDirs, }); expect(instructions.mixins[0].sourceFile).to.eql(appJS); @@ -1288,11 +1286,11 @@ describe('compiler', function() { describe(' - mixinSources', function() { beforeEach(function() { appdir.createConfigFilesSync({}, {}, { - Car: { dataSource: 'db' } + Car: { dataSource: 'db' }, }); appdir.writeConfigFileSync('models/car.json', { name: 'Car', - mixins: {'TimeStamps': {} } + mixins: { 'TimeStamps': {}}, }); }); @@ -1301,7 +1299,7 @@ describe('compiler', function() { var instructions = boot.compile({ appRootDir: appdir.PATH, - mixinSources: mixinSources + mixinSources: mixinSources, }); expect(instructions.mixins[0].sourceFile).to.eql(appJS); @@ -1318,7 +1316,7 @@ describe('compiler', function() { }); it('resolves module relative path in `mixinSources` option', - function() { + function() { verifyMixinIsFoundViaMixinSources( 'node_modules/custom-mixins/time-stamps.js', ['custom-mixins']); @@ -1327,11 +1325,11 @@ describe('compiler', function() { it('supports `mixins` option in `model-config.json`', function() { appdir.createConfigFilesSync({}, {}, { _meta: { - mixins: ['./custom-mixins'] + mixins: ['./custom-mixins'], }, Car: { - dataSource: 'db' - } + dataSource: 'db', + }, }); var appJS = appdir.writeFileSync('custom-mixins/time-stamps.js', ''); @@ -1357,12 +1355,12 @@ describe('compiler', function() { it('loads mixins from model using mixin name in JSON file', function() { var appJS = appdir.writeFileSync('mixins/time-stamps.js', ''); appdir.writeConfigFileSync('mixins/time-stamps.json', { - name: 'Timestamping' + name: 'Timestamping', }); appdir.writeConfigFileSync('models/car.json', { name: 'Car', - mixins: {'Timestamping': {} } + mixins: { 'Timestamping': {}}, }); var instructions = boot.compile(appdir.PATH); @@ -1371,13 +1369,13 @@ describe('compiler', function() { }); it('loads mixin only once for dirs common to mixinDirs & mixinSources', - function() { + function() { var appJS = appdir.writeFileSync('custom-mixins/time-stamps.js', ''); var options = { appRootDir: appdir.PATH, mixinDirs: ['./custom-mixins'], - mixinSources: ['./custom-mixins'] + mixinSources: ['./custom-mixins'], }; var instructions = boot.compile(options); @@ -1386,14 +1384,14 @@ describe('compiler', function() { }); it('loads mixin from mixinSources, when it is also found in mixinDirs', - function() { + function() { appdir.writeFileSync('mixinDir/time-stamps.js', ''); var appJS = appdir.writeFileSync('mixinSource/time-stamps.js', ''); var options = { appRootDir: appdir.PATH, mixinDirs: ['./mixinDir'], - mixinSources: ['./mixinSource'] + mixinSources: ['./mixinSource'], }; var instructions = boot.compile(options); @@ -1407,7 +1405,7 @@ describe('compiler', function() { var options = { appRootDir: appdir.PATH, - mixinSources: ['./mixins1', './mixins2'] + mixinSources: ['./mixins1', './mixins2'], }; var instructions = boot.compile(options); @@ -1436,7 +1434,7 @@ describe('compiler', function() { var mixinNames = mixins.map(getNameProperty); expect(mixinNames).to.eql([ - 'CamelCase', 'Foo', 'PascalCase', 'SpaceName', 'TimeStamps' + 'CamelCase', 'Foo', 'PascalCase', 'SpaceName', 'TimeStamps', ]); }); @@ -1448,7 +1446,7 @@ describe('compiler', function() { var mixinNames = mixins.map(getNameProperty); expect(mixinNames).to.eql([ - 'camel-case', 'foo', 'pascal-case', 'space-name', 'time-stamps' + 'camel-case', 'foo', 'pascal-case', 'space-name', 'time-stamps', ]); }); @@ -1461,7 +1459,7 @@ describe('compiler', function() { var mixinNames = mixins.map(getNameProperty); expect(mixinNames).to.eql([ - 'CAMELCASE', 'FOO', 'PASCALCASE', 'SPACE NAME', 'TIME-STAMPS' + 'CAMELCASE', 'FOO', 'PASCALCASE', 'SPACE NAME', 'TIME-STAMPS', ]); }); @@ -1473,7 +1471,7 @@ describe('compiler', function() { var mixinNames = mixins.map(getNameProperty); expect(mixinNames).to.eql([ - 'camelCase', 'foo', 'PascalCase', 'space name', 'time-stamps' + 'camelCase', 'foo', 'PascalCase', 'space name', 'time-stamps', ]); }); @@ -1485,7 +1483,7 @@ describe('compiler', function() { var mixinNames = mixins.map(getNameProperty); expect(mixinNames).to.eql([ - 'camelCase', 'foo', 'PascalCase', 'space name', 'time-stamps' + 'camelCase', 'foo', 'PascalCase', 'space name', 'time-stamps', ]); }); @@ -1496,7 +1494,7 @@ describe('compiler', function() { var mixinNames = mixins.map(getNameProperty); expect(mixinNames).to.eql([ - 'CamelCase', 'Foo', 'PascalCase', 'SpaceName', 'TimeStamps' + 'CamelCase', 'Foo', 'PascalCase', 'SpaceName', 'TimeStamps', ]); }); @@ -1510,10 +1508,10 @@ describe('compiler', function() { it('overrides default mixin name, by `name` in JSON', function() { appdir.writeFileSync('mixins/foo.js', ''); - appdir.writeConfigFileSync('mixins/foo.json', {name: 'fooBar'}); + appdir.writeConfigFileSync('mixins/foo.json', { name: 'fooBar' }); var options = { appRootDir: appdir.PATH, - mixinDirs: ['./mixins'] + mixinDirs: ['./mixins'], }; var instructions = boot.compile(options); @@ -1537,25 +1535,24 @@ describe('compiler', function() { { name: 'FooBar', description: 'JSON file name same as JS file name', - sourceFile: appJS - } + sourceFile: appJS, + }, ]); }); }); }); describe('for middleware', function() { - function testMiddlewareRegistration(middlewareId, sourceFile) { var json = { initial: { }, custom: { - } + }, }; json.custom[middlewareId] = { - params: 'some-config-data' + params: 'some-config-data', }; appdir.writeConfigFileSync('middleware.json', json); @@ -1569,10 +1566,10 @@ describe('compiler', function() { sourceFile: sourceFile, config: { phase: 'custom', - params: 'some-config-data' - } - } - ] + params: 'some-config-data', + }, + }, + ], }); } @@ -1596,8 +1593,8 @@ describe('compiler', function() { it('fails when a module middleware cannot be resolved', function() { appdir.writeConfigFileSync('middleware.json', { final: { - 'loopback/path-does-not-exist': { } - } + 'loopback/path-does-not-exist': { }, + }, }); expect(function() { boot.compile(appdir.PATH); }) @@ -1605,13 +1602,13 @@ describe('compiler', function() { }); it('does not fail when an optional middleware cannot be resolved', - function() { + function() { appdir.writeConfigFileSync('middleware.json', { final: { 'loopback/path-does-not-exist': { - optional: 'this middleware is optional' - } - } + optional: 'this middleware is optional', + }, + }, }); expect(function() { boot.compile(appdir.PATH); }) @@ -1622,8 +1619,8 @@ describe('compiler', function() { function() { appdir.writeConfigFileSync('middleware.json', { final: { - 'loopback#path-does-not-exist': { } - } + 'loopback#path-does-not-exist': { }, + }, }); expect(function() { @@ -1637,9 +1634,9 @@ describe('compiler', function() { appdir.writeConfigFileSync('middleware.json', { final: { 'loopback#path-does-not-exist': { - optional: 'this middleware is optional' - } - } + optional: 'this middleware is optional', + }, + }, }); expect(function() { boot.compile(appdir.PATH); }) @@ -1651,8 +1648,8 @@ describe('compiler', function() { appdir.writeConfigFileSync('./middleware.json', { routes: { // resolves to ./my-middleware.js - './my-middleware': { } - } + './my-middleware': { }, + }, }); var instructions = boot.compile(appdir.PATH); @@ -1661,8 +1658,8 @@ describe('compiler', function() { phases: ['routes'], middleware: [{ sourceFile: path.resolve(appdir.PATH, 'my-middleware.js'), - config: { phase: 'routes' } - }] + config: { phase: 'routes' }, + }], }); }); @@ -1671,26 +1668,26 @@ describe('compiler', function() { routes: { './middleware': { params: { - key: 'initial value' - } - } - } + key: 'initial value', + }, + }, + }, }); appdir.writeConfigFileSync('./middleware.local.json', { routes: { './middleware': { params: { - key: 'custom value' - } - } - } + key: 'custom value', + }, + }, + }, }); var instructions = boot.compile(appdir.PATH); expectFirstMiddlewareParams(instructions).to.eql({ - key: 'custom value' + key: 'custom value', }); }); @@ -1699,18 +1696,18 @@ describe('compiler', function() { routes: { './middleware': { params: { - key: 'initial value' - } - } - } + key: 'initial value', + }, + }, + }, }); appdir.writeConfigFileSync('./middleware.local.json', { routes: { './middleware': { - enabled: false - } - } + enabled: false, + }, + }, }); var instructions = boot.compile(appdir.PATH); @@ -1729,19 +1726,19 @@ describe('compiler', function() { config: { phase: 'routes', params: { - key: 'initial value' - } - } + key: 'initial value', + }, + }, }, { sourceFile: path.resolve(appdir.PATH, 'middleware'), config: { phase: 'routes', params: { - key: 'custom value' - } - } - } + key: 'custom value', + }, + }, + }, ]); } @@ -1750,20 +1747,20 @@ describe('compiler', function() { routes: { './middleware': [{ params: { - key: 'initial value' - } - }] - } + key: 'initial value', + }, + }], + }, }); appdir.writeConfigFileSync('./middleware.local.json', { routes: { './middleware': [{ params: { - key: 'custom value' - } - }] - } + key: 'custom value', + }, + }], + }, }); verifyMiddlewareConfig(); @@ -1774,20 +1771,20 @@ describe('compiler', function() { routes: { './middleware': { params: { - key: 'initial value' - } - } - } + key: 'initial value', + }, + }, + }, }); appdir.writeConfigFileSync('./middleware.local.json', { routes: { './middleware': [{ params: { - key: 'custom value' - } - }] - } + key: 'custom value', + }, + }], + }, }); verifyMiddlewareConfig(); @@ -1798,20 +1795,20 @@ describe('compiler', function() { routes: { './middleware': [{ params: { - key: 'initial value' - } - }] - } + key: 'initial value', + }, + }], + }, }); appdir.writeConfigFileSync('./middleware.local.json', { routes: { './middleware': { params: { - key: 'custom value' - } - } - } + key: 'custom value', + }, + }, + }, }); verifyMiddlewareConfig(); @@ -1820,18 +1817,18 @@ describe('compiler', function() { it('merges config.params array to empty object', function() { appdir.writeConfigFileSync('./middleware.json', { routes: { - './middleware': {} - } + './middleware': {}, + }, }); appdir.writeConfigFileSync('./middleware.local.json', { routes: { './middleware': [{ params: { - key: 'custom value' - } - }] - } + key: 'custom value', + }, + }], + }, }); var instructions = boot.compile(appdir.PATH); @@ -1843,10 +1840,10 @@ describe('compiler', function() { config: { phase: 'routes', params: { - key: 'custom value' - } - } - } + key: 'custom value', + }, + }, + }, ]); }); @@ -1856,10 +1853,10 @@ describe('compiler', function() { './middleware': [{ name: 'a', params: { - key: 'initial value' - } - }] - } + key: 'initial value', + }, + }], + }, }); appdir.writeConfigFileSync('./middleware.local.json', { @@ -1867,14 +1864,14 @@ describe('compiler', function() { './middleware': [{ name: 'a', params: { - key: 'custom value' - } + key: 'custom value', + }, }, { params: { - key: '2nd value' - } - }] - } + key: '2nd value', + }, + }], + }, }); var instructions = boot.compile(appdir.PATH); @@ -1887,19 +1884,19 @@ describe('compiler', function() { name: 'a', phase: 'routes', params: { - key: 'custom value' - } - } + key: 'custom value', + }, + }, }, { sourceFile: path.resolve(appdir.PATH, 'middleware'), config: { phase: 'routes', params: { - key: '2nd value' - } - } - } + key: '2nd value', + }, + }, + }, ]); }); @@ -1909,12 +1906,12 @@ describe('compiler', function() { }, 'custom:before': { 'loopback/server/middleware/url-not-found': { - params: 'some-config-data' - } + params: 'some-config-data', + }, }, 'custom:after': { - } + }, }); var instructions = boot.compile(appdir.PATH); @@ -1927,8 +1924,8 @@ describe('compiler', function() { require.resolve('loopback/server/middleware/url-not-found'), config: { phase: 'custom:before', - params: 'some-config-data' - } + params: 'some-config-data', + }, }]); }); @@ -1938,13 +1935,13 @@ describe('compiler', function() { 'final': { './my-middleware': [ { - params: 'first' + params: 'first', }, { - params: 'second' - } - ] - } + params: 'second', + }, + ], + }, }); var instructions = boot.compile(appdir.PATH); @@ -1955,24 +1952,24 @@ describe('compiler', function() { sourceFile: path.resolve(appdir.PATH, 'my-middleware.js'), config: { phase: 'final', - params: 'first' - } + params: 'first', + }, }, { sourceFile: path.resolve(appdir.PATH, 'my-middleware.js'), config: { phase: 'final', - params: 'second' - } - } + params: 'second', + }, + }, ]); }); it('supports shorthand notation for middleware paths', function() { appdir.writeConfigFileSync('middleware.json', { 'final': { - 'loopback#url-not-found': {} - } + 'loopback#url-not-found': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -1985,8 +1982,8 @@ describe('compiler', function() { appdir.writeConfigFileSync('middleware.json', { 'routes': { './middleware/index#myMiddleware': { - } - } + }, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2003,8 +2000,8 @@ describe('compiler', function() { function() { appdir.writeConfigFileSync('middleware.json', { 'final': { - 'loopback#errorHandler': {} - } + 'loopback#errorHandler': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2025,8 +2022,8 @@ describe('compiler', function() { appdir.writeConfigFileSync('middleware.json', { 'initial': { - 'handler': {} - } + 'handler': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2041,8 +2038,8 @@ describe('compiler', function() { appdir.writeFileSync('node_modules/my-middleware.js', ''); appdir.writeConfigFileSync('middleware.json', { 'routes': { - './my-middleware': {} - } + './my-middleware': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2053,13 +2050,13 @@ describe('compiler', function() { }); it('does not treat module relative path as `appRootDir` relative', - function() { + function() { appdir.writeFileSync('./my-middleware.js', ''); var moduleJS = appdir.writeFileSync('node_modules/my-middleware.js', ''); appdir.writeConfigFileSync('middleware.json', { 'routes': { - 'my-middleware': {} - } + 'my-middleware': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2073,8 +2070,8 @@ describe('compiler', function() { var coffee = appdir.writeFileSync('my-middleware.coffee', ''); appdir.writeConfigFileSync('middleware.json', { 'routes': { - './my-middleware': {} - } + './my-middleware': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2084,14 +2081,14 @@ describe('compiler', function() { }); it('loads coffeescript from middleware under node_modules', - function() { + function() { var file = appdir.writeFileSync('node_modules/my-middleware/index.coffee', ''); appdir.writeFileSync('node_modules/my-middleware/index.json', ''); appdir.writeConfigFileSync('middleware.json', { 'routes': { - 'my-middleware': {} - } + 'my-middleware': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2102,13 +2099,13 @@ describe('compiler', function() { }); it('prefers coffeescript over json for relative middleware path', - function() { + function() { var coffee = appdir.writeFileSync('my-middleware.coffee', ''); appdir.writeFileSync('my-middleware.json', ''); appdir.writeConfigFileSync('middleware.json', { 'routes': { - './my-middleware': {} - } + './my-middleware': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2119,14 +2116,14 @@ describe('compiler', function() { }); it('prefers coffeescript over json for module relative middleware path', - function() { + function() { var coffee = appdir.writeFileSync('node_modules/my-middleware.coffee', ''); appdir.writeFileSync('node_modules/my-middleware.json', ''); appdir.writeConfigFileSync('middleware.json', { 'routes': { - 'my-middleware': {} - } + 'my-middleware': {}, + }, }); var instructions = boot.compile(appdir.PATH); @@ -2139,7 +2136,7 @@ describe('compiler', function() { describe('config with relative paths in params', function() { var RELATIVE_PATH_PARAMS = [ '$!./here', - '$!../there' + '$!../there', ]; var absolutePathParams; @@ -2181,9 +2178,9 @@ describe('compiler', function() { it('converts paths in nested properties', function() { givenMiddlewareEntrySync({ params: { nestedObject: { - path: RELATIVE_PATH_PARAMS[0] + path: RELATIVE_PATH_PARAMS[0], }, - nestedArray: RELATIVE_PATH_PARAMS + nestedArray: RELATIVE_PATH_PARAMS, }}); var instructions = boot.compile(appdir.PATH); @@ -2191,15 +2188,15 @@ describe('compiler', function() { expectFirstMiddlewareParams(instructions) .to.eql({ nestedObject: { - path: absolutePathParams[0] + path: absolutePathParams[0], }, - nestedArray: absolutePathParams + nestedArray: absolutePathParams, }); }); it('does not convert values not starting with `./` or `../`', function() { var PARAMS = ['$!.somerc', '$!/root', '$!hello!']; - givenMiddlewareEntrySync({ params: PARAMS}); + givenMiddlewareEntrySync({ params: PARAMS }); var instructions = boot.compile(appdir.PATH); @@ -2212,15 +2209,15 @@ describe('compiler', function() { it('loads component configs from multiple files', function() { appdir.createConfigFilesSync(); appdir.writeConfigFileSync('component-config.json', { - debug: { option: 'value' } + debug: { option: 'value' }, }); appdir.writeConfigFileSync('component-config.local.json', { - debug: { local: 'applied' } + debug: { local: 'applied' }, }); var env = process.env.NODE_ENV || 'development'; appdir.writeConfigFileSync('component-config.' + env + '.json', { - debug: { env: 'applied' } + debug: { env: 'applied' }, }); var instructions = boot.compile(appdir.PATH); @@ -2231,14 +2228,14 @@ describe('compiler', function() { config: { option: 'value', local: 'applied', - env: 'applied' - } + env: 'applied', + }, }); }); it('loads component relative to appRootDir', function() { appdir.writeConfigFileSync('./component-config.json', { - './index': { } + './index': { }, }); var appJS = appdir.writeConfigFileSync('index.js', ''); @@ -2250,7 +2247,7 @@ describe('compiler', function() { it('loads component relative to node modules', function() { appdir.writeConfigFileSync('component-config.json', { - 'mycomponent': { } + 'mycomponent': { }, }); var js = appdir.writeConfigFileSync('node_modules/mycomponent/index.js', ''); @@ -2262,9 +2259,9 @@ describe('compiler', function() { }); it('retains backward compatibility for non-relative path in `appRootDir`', - function() { + function() { appdir.writeConfigFileSync('component-config.json', { - 'my-component/component.js': { } + 'my-component/component.js': { }, }); appdir.writeConfigFileSync('./my-component/component.js', ''); @@ -2273,9 +2270,9 @@ describe('compiler', function() { }); it('prefers coffeescript over json for relative path component', - function() { + function() { appdir.writeConfigFileSync('component-config.json', { - './component': { } + './component': { }, }); var coffee = appdir.writeFileSync('component.coffee', ''); @@ -2289,9 +2286,9 @@ describe('compiler', function() { }); it('prefers coffeescript over json for module relative component path', - function() { + function() { appdir.writeConfigFileSync('component-config.json', { - 'component': { } + 'component': { }, }); var coffee = appdir.writeFileSync('node_modules/component.coffee', ''); @@ -2303,7 +2300,6 @@ describe('compiler', function() { expect(instructions.components[0]).have.property( 'sourceFile', coffee); }); - }); }); @@ -2315,8 +2311,8 @@ function givenMiddlewareEntrySync(config) { appdir.writeConfigFileSync('middleware.json', { initial: { // resolves to ./middleware.json - './middleware': config - } + './middleware': config, + }, }); } diff --git a/test/executor.test.js b/test/executor.test.js index 99ea363..867000b 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -37,22 +37,22 @@ describe('executor', function() { host: '127.0.0.1', restApiRoot: '/rest-api', foo: { bar: 'bat' }, - baz: true + baz: true, }, models: [ { name: 'User', config: { - dataSource: 'the-db' - } - } + dataSource: 'the-db', + }, + }, ], dataSources: { 'the-db': { connector: 'memory', - defaultForType: 'db' - } - } + defaultForType: 'db', + }, + }, }); describe('when booting', function() { @@ -109,9 +109,9 @@ describe('executor', function() { name: 'Customer', base: 'User', }, - sourceFile: path.resolve(appdir.PATH, 'models', 'Customer.js') - } - ] + sourceFile: path.resolve(appdir.PATH, 'models', 'Customer.js'), + }, + ], })); expect(app.models.Customer).to.exist(); @@ -127,9 +127,9 @@ describe('executor', function() { name: 'Vehicle', config: undefined, definition: { - name: 'Vehicle' + name: 'Vehicle', }, - sourceFile: undefined + sourceFile: undefined, }, { name: 'Car', @@ -138,9 +138,9 @@ describe('executor', function() { name: 'Car', base: 'Vehicle', }, - sourceFile: undefined + sourceFile: undefined, }, - ] + ], })); expect(Object.keys(app.models)).to.eql(['Car']); @@ -166,15 +166,15 @@ describe('executor', function() { name: 'Customer', config: { dataSource: 'db' }, definition: { name: 'Customer' }, - sourceFile: path.resolve(appdir.PATH, 'models', 'Customer.js') + sourceFile: path.resolve(appdir.PATH, 'models', 'Customer.js'), }, { name: 'UniqueName', config: { dataSource: 'db' }, definition: { name: 'UniqueName' }, - sourceFile: undefined - } - ] + sourceFile: undefined, + }, + ], })); expect(app.models.Customer._modelsWhenAttached).to.include('UniqueName'); @@ -188,9 +188,9 @@ describe('executor', function() { name: 'LocalCustomer', config: { dataSource: 'db' }, definition: { name: 'LocalCustomer' }, - sourceFile: undefined - } - ] + sourceFile: undefined, + }, + ], })); expect(Object.keys(loopback.registry.modelBuilder.models), 'global models') @@ -204,7 +204,7 @@ describe('executor', function() { 'require("doesnt-exist"); module.exports = {};'); function doBoot() { - boot.execute(app, someInstructions({ files: { boot: [file] } })); + boot.execute(app, someInstructions({ files: { boot: [file] }})); } expect(doBoot).to.throw(/Cannot find module \'doesnt-exist\'/); @@ -236,7 +236,7 @@ describe('executor', function() { require.resolve('loopback/common/models/user.json') ), config: { dataSource: 'db' }, - sourceFile: require.resolve('loopback/common/models/user.js') + sourceFile: require.resolve('loopback/common/models/user.js'), }; builtinModel.definition.redefined = true; @@ -260,7 +260,7 @@ describe('executor', function() { 'barLoaded', 'barSyncLoaded', 'fooLoaded', - 'barStarted' + 'barStarted', ]); // bar finished happens in the next tick @@ -272,7 +272,7 @@ describe('executor', function() { 'fooLoaded', 'barStarted', 'barFinished', - 'barSyncExecuted' + 'barSyncExecuted', ]); done(); }, 10); @@ -288,7 +288,7 @@ describe('executor', function() { 'fooLoaded', 'barStarted', 'barFinished', - 'barSyncExecuted' + 'barSyncExecuted', ]); done(); }); @@ -306,11 +306,11 @@ describe('executor', function() { 'function(Model, options) {}'); appdir.writeConfigFileSync('custom-mixins/time-stamps.json', { - name: 'Timestamping' + name: 'Timestamping', }); options = { - appRootDir: appdir.PATH + appRootDir: appdir.PATH, }; }); @@ -357,8 +357,8 @@ describe('executor', function() { boot.execute(app, someInstructions({ config: { port: undefined, - host: undefined - } + host: undefined, + }, })); } @@ -388,6 +388,7 @@ describe('executor', function() { it('should prioritize host sources', function() { // jscs:disable requireCamelCaseOrUpperCaseIdentifiers + /*eslint-disable camelcase*/ process.env.npm_config_host = randomHost(); process.env.OPENSHIFT_SLS_IP = randomHost(); process.env.OPENSHIFT_NODEJS_IP = randomHost(); @@ -397,9 +398,11 @@ describe('executor', function() { bootWithDefaults(); assert.equal(app.get('host'), process.env.npm_config_host); + /*eslint-enable camelcase*/ }); it('should prioritize port sources', function() { + /*eslint-disable camelcase*/ process.env.npm_config_port = randomPort(); process.env.OPENSHIFT_SLS_PORT = randomPort(); process.env.OPENSHIFT_NODEJS_PORT = randomPort(); @@ -409,6 +412,7 @@ describe('executor', function() { bootWithDefaults(); assert.equal(app.get('port'), process.env.npm_config_port); + /*eslint-enable camelcase*/ }); function randomHost() { @@ -420,19 +424,19 @@ describe('executor', function() { } it('should honor 0 for free port', function() { - boot.execute(app, someInstructions({ config: { port: 0 } })); + boot.execute(app, someInstructions({ config: { port: 0 }})); assert.equal(app.get('port'), 0); }); it('should default to port 3000', function() { - boot.execute(app, someInstructions({ config: { port: undefined } })); + boot.execute(app, someInstructions({ config: { port: undefined }})); assert.equal(app.get('port'), 3000); }); it('should respect named pipes port values in ENV', function() { var NAMED_PORT = '\\.\\pipe\\test'; process.env.PORT = NAMED_PORT; - boot.execute(app, someInstructions({ config: { port: 3000 } })); + boot.execute(app, someInstructions({ config: { port: 3000 }})); assert.equal(app.get('port'), NAMED_PORT); }); }); @@ -479,13 +483,13 @@ describe('executor', function() { it('should parse config variables in an object', function(done) { boot.execute(app, simpleMiddlewareConfig('routes', - { info: { path: '${restApiRoot}' } } + { info: { path: '${restApiRoot}' }} )); supertest(app).get('/').end(function(err, res) { if (err) return done(err); expect(res.body.info).to.eql({ - path: app.get('restApiRoot') + path: app.get('restApiRoot'), }); done(); }); @@ -493,13 +497,13 @@ describe('executor', function() { it('should parse config variables in a nested object', function(done) { boot.execute(app, simpleMiddlewareConfig('routes', - { nested: { info: { path: '${restApiRoot}' } } } + { nested: { info: { path: '${restApiRoot}' }}} )); supertest(app).get('/').end(function(err, res) { if (err) return done(err); expect(res.body.nested).to.eql({ - info: { path: app.get('restApiRoot') } + info: { path: app.get('restApiRoot') }, }); done(); }); @@ -509,7 +513,7 @@ describe('executor', function() { var invalidDataTypes = [undefined, function() {}]; async.each(invalidDataTypes, function(invalidDataType, cb) { var config = simpleMiddlewareConfig('routes', { - path: invalidDataType + path: invalidDataType, }); boot.execute(app, config); @@ -525,7 +529,7 @@ describe('executor', function() { it('should parse valid config variables', function(done) { var config = simpleMiddlewareConfig('routes', { - props: ['a', '${vVar}', 1, true, function() {}, {x:1, y: '${y}'}] + props: ['a', '${vVar}', 1, true, function() {}, { x: 1, y: '${y}' }], }); boot.execute(app, config); @@ -552,7 +556,6 @@ describe('executor', function() { }); describe('with component-config.json', function() { - it('should parse a simple config variable', function(done) { boot.execute(app, simpleComponentConfig( { path: '${restApiRoot}' } @@ -594,13 +597,13 @@ describe('executor', function() { it('should parse config variables in an object', function(done) { boot.execute(app, simpleComponentConfig( - { info: { path: '${restApiRoot}' } } + { info: { path: '${restApiRoot}' }} )); supertest(app).get('/component').end(function(err, res) { if (err) return done(err); expect(res.body.info).to.eql({ - path: app.get('restApiRoot') + path: app.get('restApiRoot'), }); done(); }); @@ -608,18 +611,17 @@ describe('executor', function() { it('should parse config variables in a nested object', function(done) { boot.execute(app, simpleComponentConfig( - { nested: { info: { path: '${restApiRoot}' } } } + { nested: { info: { path: '${restApiRoot}' }}} )); supertest(app).get('/component').end(function(err, res) { if (err) return done(err); expect(res.body.nested).to.eql({ - info: { path: app.get('restApiRoot') } + info: { path: app.get('restApiRoot') }, }); done(); }); }); - }); it('calls function exported by boot/init.js', function() { @@ -627,7 +629,7 @@ describe('executor', function() { 'module.exports = function(app) { app.fnCalled = true; };'); delete app.fnCalled; - boot.execute(app, someInstructions({ files: { boot: [file] } })); + boot.execute(app, someInstructions({ files: { boot: [file] }})); expect(app.fnCalled, 'exported fn was called').to.be.true(); }); @@ -642,33 +644,33 @@ describe('executor', function() { sourceFile: pushNamePath, config: { phase: 'initial', - params: 'initial' - } + params: 'initial', + }, }, { sourceFile: pushNamePath, config: { phase: 'custom', - params: 'custom' - } + params: 'custom', + }, }, { sourceFile: pushNamePath, config: { phase: 'routes', - params: 'routes' - } + params: 'routes', + }, }, { sourceFile: pushNamePath, config: { phase: 'routes', enabled: false, - params: 'disabled' - } - } - ] - } + params: 'disabled', + }, + }, + ], + }, })); supertest(app) @@ -682,7 +684,6 @@ describe('executor', function() { }); it('configures middleware using shortform', function(done) { - boot.execute(app, someInstructions({ middleware: { middleware: [ @@ -691,11 +692,11 @@ describe('executor', function() { fragment: 'static', config: { phase: 'files', - params: path.join(__dirname, './fixtures/simple-app/client/') - } - } - ] - } + params: path.join(__dirname, './fixtures/simple-app/client/'), + }, + }, + ], + }, })); supertest(app) @@ -725,8 +726,8 @@ describe('executor', function() { it('configures components', function() { appdir.writeConfigFileSync('component-config.json', { './components/test-component': { - option: 'value' - } + option: 'value', + }, }); appdir.writeFileSync('components/test-component/index.js', @@ -743,7 +744,7 @@ describe('executor', function() { it('disables component when configuration is not set', function() { appdir.writeConfigFileSync('component-config.json', { - './components/test-component': false + './components/test-component': false, }); appdir.writeFileSync('components/test-component/index.js', @@ -758,10 +759,10 @@ describe('executor', function() { it('disable component if overrided by production configuration', function() { appdir.writeConfigFileSync('component-config.json', { - './components/test-component': {} + './components/test-component': {}, }); appdir.writeConfigFileSync('component-config.production.json', { - './components/test-component': null + './components/test-component': null, }); appdir.writeFileSync('components/test-component/index.js', @@ -785,11 +786,11 @@ describe('executor', function() { sourceFile: passportPath, fragment: 'initialize', config: { - phase: 'auth:before' - } - } - ] - } + phase: 'auth:before', + }, + }, + ], + }, })); supertest(app) @@ -808,7 +809,6 @@ describe('executor', function() { }); }); }); - }); function simpleMiddlewareConfig(phase, paths, params) { @@ -819,7 +819,7 @@ function simpleMiddlewareConfig(phase, paths, params) { var config = { phase: phase, - params: params + params: params, }; if (paths) config.paths = paths; @@ -831,9 +831,9 @@ function simpleMiddlewareConfig(phase, paths, params) { { sourceFile: path.join(__dirname, './fixtures/simple-middleware.js'), config: config, - } - ] - } + }, + ], + }, }); } @@ -842,9 +842,9 @@ function simpleComponentConfig(config) { components: [ { sourceFile: path.join(__dirname, './fixtures/simple-component.js'), - config: config - } - ] + config: config, + }, + ], }); } @@ -869,12 +869,12 @@ function someInstructions(values) { var result = { config: values.config || {}, models: values.models || [], - dataSources: values.dataSources || { db: { connector: 'memory' } }, + dataSources: values.dataSources || { db: { connector: 'memory' }}, middleware: values.middleware || { phases: [], middleware: [] }, components: values.components || [], files: { - boot: [] - } + boot: [], + }, }; if (values.env) @@ -898,6 +898,6 @@ function envAppInstructions() { fs.copySync(ENV_APP, appdir.PATH); return boot.compile({ appRootDir: appdir.PATH, - env: 'test' + env: 'test', }); } diff --git a/test/fixtures/browser-app-2/app.js b/test/fixtures/browser-app-2/app.js index f33937a..9905979 100644 --- a/test/fixtures/browser-app-2/app.js +++ b/test/fixtures/browser-app-2/app.js @@ -5,5 +5,5 @@ var app = module.exports = loopback(); boot(app, { appId: 'browserApp2', - appRootDir: __dirname + appRootDir: __dirname, }); diff --git a/test/fixtures/browser-app/mixins/time-stamps.js b/test/fixtures/browser-app/mixins/time-stamps.js index c126e8b..6ba0a1a 100644 --- a/test/fixtures/browser-app/mixins/time-stamps.js +++ b/test/fixtures/browser-app/mixins/time-stamps.js @@ -1,5 +1,3 @@ module.exports = function(Model, options) { - Model.timeStampsMixin = true; - }; diff --git a/test/fixtures/passport.js b/test/fixtures/passport.js index 3dd8c13..35e7060 100644 --- a/test/fixtures/passport.js +++ b/test/fixtures/passport.js @@ -5,7 +5,7 @@ var framework = { res.setHeader('passport', 'initialized'); next(); }; - } + }, }; var Passport = function() { diff --git a/test/fixtures/simple-component.js b/test/fixtures/simple-component.js index 952e5ae..a09da14 100644 --- a/test/fixtures/simple-component.js +++ b/test/fixtures/simple-component.js @@ -1,7 +1,5 @@ module.exports = function(loopbackApp, params) { - loopbackApp.use('/component', function(req, res, next) { res.send(params); }); - }; diff --git a/test/helpers/appdir.js b/test/helpers/appdir.js index a52a606..a8955a6 100644 --- a/test/helpers/appdir.js +++ b/test/helpers/appdir.js @@ -27,8 +27,8 @@ appdir.createConfigFilesSync = function(appConfig, dataSources, models) { dataSources = extend({ db: { connector: 'memory', - defaultForType: 'db' - } + defaultForType: 'db', + }, }, dataSources); appdir.writeConfigFileSync ('datasources.json', dataSources); diff --git a/test/helpers/browser.js b/test/helpers/browser.js index 40bd5c4..bbcd0f2 100644 --- a/test/helpers/browser.js +++ b/test/helpers/browser.js @@ -8,14 +8,14 @@ function createContext() { localStorage: { // used by `debug` module - debug: process.env.DEBUG + debug: process.env.DEBUG, }, // used by DataSource.prototype.ready setTimeout: setTimeout, // used by `debug` module - document: { documentElement: { style: {} } }, + document: { documentElement: { style: {}}}, // used by `debug` module navigator: { userAgent: 'sandbox' }, @@ -39,9 +39,9 @@ function createContext() { _logs: { log: [], warn: [], - error: [] + error: [], }, - } + }, }; // `window` is used by loopback to detect browser runtime @@ -52,9 +52,10 @@ function createContext() { exports.createContext = createContext; function printContextLogs(context) { - for (var k in context.console._logs) { + var k, ix; // see https://github.com/eslint/eslint/issues/5744 + for (k in context.console._logs) { var items = context.console._logs[k]; - for (var ix in items) { + for (ix in items) { console[k].apply(console, items[ix]); } } From 4a815deb27e66ca4c08eeccdc2bc8d63892d8df3 Mon Sep 17 00:00:00 2001 From: David Cheung Date: Mon, 28 Mar 2016 15:46:01 -0400 Subject: [PATCH 04/10] Dynamic datasources.json from ENV and config.json Let environment variables override configuration set by config.json and/or app.set() Behavior changes - datasources.json now support dynamic configuration through env-vars and config.json - component-config.json will first consider env-var for resolving dynamic conf, then fallback to config.json - middleware.json will first consider env-var for resolving dynamic conf, then fallback to config.json - for all the dynamic confg, unresolved conf will return as `undefined` Example: Consider the following server/datasources.json ``` { "mysql" : { "name" : "mysql_db", "host" : "${MYSQL_DB_HOST}", ... } } ``` Now you can provide the parameter through an environment variable: ``` $ MYSQL_DB_HOST=127.0.0.1 node . ``` or you can set the value in server/config.json ``` { "MYSQL_DB_HOST": "127.0.0.1" } ``` --- lib/executor.js | 39 +++++++++-- test/executor.test.js | 150 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 7 deletions(-) diff --git a/lib/executor.js b/lib/executor.js index dfc7379..72f917f 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -171,6 +171,10 @@ function applyAppConfig(app, instructions) { function setupDataSources(app, instructions) { forEachKeyedObject(instructions.dataSources, function(key, obj) { + var opts = { + useEnvVars: true, + }; + obj = getUpdatedConfigObject(app, obj, opts); app.dataSource(key, obj); }); } @@ -330,24 +334,42 @@ function setupMiddleware(app, instructions) { } assert(typeof factory === 'function', 'Middleware factory must be a function'); - data.config = getUpdatedConfigObject(app, data.config); + var opts = { + useEnvVars: true, + }; + data.config = getUpdatedConfigObject(app, data.config, opts); app.middlewareFromConfig(factory, data.config); }); } -function getUpdatedConfigObject(app, config) { +function getUpdatedConfigObject(app, config, opts) { var DYNAMIC_CONFIG_PARAM = /\$\{(\w+)\}$/; + var useEnvVars = opts && opts.useEnvVars; function getConfigVariable(param) { var configVariable = param; var match = configVariable.match(DYNAMIC_CONFIG_PARAM); if (match) { - var appValue = app.get(match[1]); - if (appValue !== undefined) { + var varName = match[1]; + if (useEnvVars && process.env[varName] !== undefined) { + debug('Dynamic Configuration: Resolved via process.env: %s as %s', + process.env[varName], param); + configVariable = process.env[varName]; + } else if (app.get(varName) !== undefined) { + debug('Dynamic Configuration: Resolved via app.get(): %s as %s', + app.get(varName), param); + var appValue = app.get(varName); configVariable = appValue; } else { - console.warn('%s does not resolve to a valid value. ' + - '"%s" must be resolvable by app.get().', param, match[1]); + // previously it returns the original string such as "${restApiRoot}" + // it will now return `undefined`, for the use case of + // dynamic datasources url:`undefined` to fallback to other parameters + configVariable = undefined; + console.warn('%s does not resolve to a valid value, returned as %s. ' + + '"%s" must be resolvable in Environment variable or by app.get().', + param, configVariable, varName); + debug('Dynamic Configuration: Cannot resolve variable for `%s`, ' + + 'returned as %s', varName, configVariable); } } return configVariable; @@ -394,7 +416,10 @@ function setupComponents(app, instructions) { instructions.components.forEach(function(data) { debug('Configuring component %j', data.sourceFile); var configFn = require(data.sourceFile); - data.config = getUpdatedConfigObject(app, data.config); + var opts = { + useEnvVars: true, + }; + data.config = getUpdatedConfigObject(app, data.config, opts); configFn(app, data.config); }); } diff --git a/test/executor.test.js b/test/executor.test.js index 867000b..dde248e 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -442,6 +442,10 @@ describe('executor', function() { }); describe('with middleware.json', function() { + beforeEach(function() { + delete process.env.restApiRoot; + }); + it('should parse a simple config variable', function(done) { boot.execute(app, simpleMiddlewareConfig('routes', { path: '${restApiRoot}' } @@ -454,6 +458,36 @@ describe('executor', function() { }); }); + it('should parse simple config variable from env var', function(done) { + process.env.restApiRoot = '/url-from-env-var'; + boot.execute(app, simpleMiddlewareConfig('routes', + { path: '${restApiRoot}' } + )); + + supertest(app).get('/url-from-env-var').end(function(err, res) { + if (err) return done(err); + expect(res.body.path).to.equal('/url-from-env-var'); + done(); + }); + }); + + it('dynamic variable from `env var` should have' + + ' precedence over app.get()', function(done) { + process.env.restApiRoot = '/url-from-env-var'; + var bootInstructions; + bootInstructions = simpleMiddlewareConfig('routes', + { path: '${restApiRoot}' }); + bootInstructions.config = { restApiRoot: '/url-from-config' }; + boot.execute(app, someInstructions(bootInstructions)); + + supertest(app).get('/url-from-env-var').end(function(err, res) { + if (err) return done(err); + expect(app.get('restApiRoot')).to.equal('/url-from-config'); + expect(res.body.path).to.equal('/url-from-env-var'); + done(); + }); + }); + it('should parse multiple config variables', function(done) { boot.execute(app, simpleMiddlewareConfig('routes', { path: '${restApiRoot}', env: '${env}' } @@ -556,6 +590,11 @@ describe('executor', function() { }); describe('with component-config.json', function() { + beforeEach(function() { + delete process.env.DYNAMIC_ENVVAR; + delete process.env.DYNAMIC_VARIABLE; + }); + it('should parse a simple config variable', function(done) { boot.execute(app, simpleComponentConfig( { path: '${restApiRoot}' } @@ -568,6 +607,46 @@ describe('executor', function() { }); }); + it('should parse config from `env-var` and `config`', function(done) { + var bootInstructions = simpleComponentConfig( + { + path: '${restApiRoot}', + fromConfig: '${DYNAMIC_CONFIG}', + fromEnvVar: '${DYNAMIC_ENVVAR}', + } + ); + + // result should get value from config.json + bootInstructions.config['DYNAMIC_CONFIG'] = 'FOOBAR-CONFIG'; + // result should get value from env var + process.env.DYNAMIC_ENVVAR = 'FOOBAR-ENVVAR'; + + boot.execute(app, bootInstructions); + supertest(app).get('/component').end(function(err, res) { + if (err) return done(err); + expect(res.body.fromConfig).to.equal('FOOBAR-CONFIG'); + expect(res.body.fromEnvVar).to.equal('FOOBAR-ENVVAR'); + done(); + }); + }); + + it('`env-var` should have precedence over `config`', function(done) { + var key = 'DYNAMIC_VARIABLE'; + var bootInstructions = simpleComponentConfig({ + path: '${restApiRoot}', + isDynamic: '${' + key + '}', + }); + bootInstructions.config[key] = 'should be overwritten'; + process.env[key] = 'successfully overwritten'; + + boot.execute(app, bootInstructions); + supertest(app).get('/component').end(function(err, res) { + if (err) return done(err); + expect(res.body.isDynamic).to.equal('successfully overwritten'); + done(); + }); + }); + it('should parse multiple config variables', function(done) { boot.execute(app, simpleComponentConfig( { path: '${restApiRoot}', env: '${env}' } @@ -809,6 +888,77 @@ describe('executor', function() { }); }); }); + + describe('dynamic configuration for datasources.json', function() { + beforeEach(function() { + delete process.env.DYNAMIC_HOST; + delete process.env.DYNAMIC_PORT; + }); + + it('should convert dynamic variable for datasource', function(done) { + var datasource = { + mydb: { + host: '${DYNAMIC_HOST}', + port: '${DYNAMIC_PORT}', + }, + }; + var bootInstructions = { dataSources: datasource }; + + process.env.DYNAMIC_PORT = '10007'; + process.env.DYNAMIC_HOST = '123.321.123.132'; + + boot.execute(app, someInstructions(bootInstructions), function() { + expect(app.datasources.mydb.settings.host).to.equal('123.321.123.132'); + expect(app.datasources.mydb.settings.port).to.equal('10007'); + done(); + }); + }); + + it('should resolve dynamic config via app.get()', function(done) { + var datasource = { + mydb: { host: '${DYNAMIC_HOST}' }, + }; + var bootInstructions = { + config: { DYNAMIC_HOST: '127.0.0.4' }, + dataSources: datasource, + }; + boot.execute(app, someInstructions(bootInstructions), function() { + expect(app.get('DYNAMIC_HOST')).to.equal('127.0.0.4'); + expect(app.datasources.mydb.settings.host).to.equal( + '127.0.0.4'); + done(); + }); + }); + + it('should take ENV precedence over config.json', function(done) { + process.env.DYNAMIC_HOST = '127.0.0.2'; + var datasource = { + mydb: { host: '${DYNAMIC_HOST}' }, + }; + var bootInstructions = { + config: { DYNAMIC_HOST: '127.0.0.3' }, + dataSources: datasource, + }; + boot.execute(app, someInstructions(bootInstructions), function() { + expect(app.get('DYNAMIC_HOST')).to.equal('127.0.0.3'); + expect(app.datasources.mydb.settings.host).to.equal('127.0.0.2'); + done(); + }); + }); + + it('empty dynamic conf should resolve as `undefined`', function(done) { + var datasource = { + mydb: { host: '${DYNAMIC_HOST}' }, + }; + var bootInstructions = { dataSources: datasource }; + + boot.execute(app, someInstructions(bootInstructions), function() { + expect(app.get('DYNAMIC_HOST')).to.be.undefined(); + expect(app.datasources.mydb.settings.host).to.be.undefined(); + done(); + }); + }); + }); }); function simpleMiddlewareConfig(phase, paths, params) { From cc551b0c0fd307f85a28a356f37ae3a61c6c5fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Thu, 7 Apr 2016 10:28:22 +0200 Subject: [PATCH 05/10] 2.18.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dynamic datasources.json from ENV and config.json (David Cheung) * Use eslint with loopback config (Miroslav Bajtoš) --- CHANGES.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index c4b704d..8e231b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +2016-04-07, Version 2.18.0 +========================== + + * Dynamic datasources.json from ENV and config.json (David Cheung) + + * Use eslint with loopback config (Miroslav Bajtoš) + + 2016-02-23, Version 2.17.0 ========================== diff --git a/package.json b/package.json index bbc4711..0fc99e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-boot", - "version": "2.17.0", + "version": "2.18.0", "description": "Convention-based bootstrapper for LoopBack applications", "keywords": [ "StrongLoop", From 1d2649eee756ea02e5cc22554b82fd9e8f691bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mahieu?= Date: Mon, 11 Apr 2016 19:22:30 +0200 Subject: [PATCH 06/10] parse config: should ignore null values Fix #182 --- lib/executor.js | 2 ++ test/executor.test.js | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/executor.js b/lib/executor.js index 72f917f..16430d8 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -400,6 +400,8 @@ function getUpdatedConfigObject(app, config, opts) { interpolated[configKey] = value.map(interpolateVariables); } else if (typeof value === 'string') { interpolated[configKey] = getConfigVariable(value); + } else if (value === null) { + interpolated[configKey] = value; } else if (typeof value === 'object' && Object.keys(value).length) { interpolated[configKey] = interpolateVariables(value); } else { diff --git a/test/executor.test.js b/test/executor.test.js index dde248e..c61d8be 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -543,6 +543,23 @@ describe('executor', function() { }); }); + it('should parse config variables with null values', function(done) { + boot.execute(app, simpleMiddlewareConfig('routes', + { nested: { info: { path: '${restApiRoot}', some: null }}} + )); + + supertest(app).get('/').end(function(err, res) { + if (err) return done(err); + expect(res.body.nested).to.eql({ + info: { + path: app.get('restApiRoot'), + some: null, + }, + }); + done(); + }); + }); + it('should not parse invalid config variables', function(done) { var invalidDataTypes = [undefined, function() {}]; async.each(invalidDataTypes, function(invalidDataType, cb) { From 51a699af01c68d61011be2f7258e47e516c1c34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 13 Apr 2016 16:16:14 +0200 Subject: [PATCH 07/10] 2.18.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * parse config: should ignore null values (Loïc Mahieu) --- CHANGES.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 8e231b6..674e3a6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,9 @@ +2016-04-13, Version 2.18.1 +========================== + + * parse config: should ignore null values (Loïc Mahieu) + + 2016-04-07, Version 2.18.0 ========================== diff --git a/package.json b/package.json index 0fc99e4..b141228 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-boot", - "version": "2.18.0", + "version": "2.18.1", "description": "Convention-based bootstrapper for LoopBack applications", "keywords": [ "StrongLoop", From d334425ada2b073907b4a3b641bc31c3bd3f4b66 Mon Sep 17 00:00:00 2001 From: juehou Date: Thu, 14 Apr 2016 16:38:11 -0400 Subject: [PATCH 08/10] Add flag var lazyConnect to ds config --- lib/executor.js | 5 ++++ test/executor.test.js | 56 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/lib/executor.js b/lib/executor.js index 16430d8..c22e32e 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -175,6 +175,11 @@ function setupDataSources(app, instructions) { useEnvVars: true, }; obj = getUpdatedConfigObject(app, obj, opts); + var lazyConnect = process.env.LB_LAZYCONNECT_DATASOURCES; + if (lazyConnect) { + obj.lazyConnect = + lazyConnect === 'false' || lazyConnect === '0' ? false : true; + } app.dataSource(key, obj); }); } diff --git a/test/executor.test.js b/test/executor.test.js index c61d8be..1851395 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -906,6 +906,62 @@ describe('executor', function() { }); }); + describe('when booting with lazy connect', function() { + var SAMPLE_INSTRUCTION = someInstructions({ + dataSources: { + lazyConnector: { + connector: 'testLazyConnect', + name: 'lazyConnector', + }, + }, + }); + var connectTriggered = true; + + beforeEach(function() { + app.connector('testLazyConnect', { + initialize: function(dataSource, callback) { + if (dataSource.settings.lazyConnect) { + connectTriggered = false; + } else { + connectTriggered = true; + } + }, + }); + }); + + it('should trigger connect with ENV undefined', function(done) { + delete process.env.LB_LAZYCONNECT_DATASOURCES; + boot.execute(app, SAMPLE_INSTRUCTION, function() { + expect(connectTriggered).to.equal(true); + done(); + }); + }); + + it('should not trigger connect with ENV true', function(done) { + process.env.LB_LAZYCONNECT_DATASOURCES = 'true'; + boot.execute(app, SAMPLE_INSTRUCTION, function() { + expect(connectTriggered).to.equal(false); + done(); + }); + }); + + it('should trigger connect with ENV false', function(done) { + process.env.LB_LAZYCONNECT_DATASOURCES = 'false'; + boot.execute(app, SAMPLE_INSTRUCTION, function() { + expect(connectTriggered).to.equal(true); + done(); + }); + }); + + it('should trigger connect with ENV 0', function(done) { + process.env.LB_LAZYCONNECT_DATASOURCES = '0'; + boot.execute(app, SAMPLE_INSTRUCTION, function() { + expect(connectTriggered).to.equal(true); + done(); + }); + }); + }); + describe('dynamic configuration for datasources.json', function() { beforeEach(function() { delete process.env.DYNAMIC_HOST; From 5eaa9090068ea99676ca081fc177e2a877ef9337 Mon Sep 17 00:00:00 2001 From: Ryan Graham Date: Thu, 5 May 2016 21:52:36 -0700 Subject: [PATCH 09/10] update copyright notices and license --- LICENSE | 25 +++++++++++++++++++ LICENSE.md | 9 ------- browser.js | 5 ++++ index.js | 5 ++++ lib/bundler.js | 5 ++++ lib/compiler.js | 5 ++++ lib/config-loader.js | 5 ++++ lib/executor.js | 5 ++++ test/browser.multiapp.test.js | 5 ++++ test/browser.test.js | 5 ++++ test/compiler.test.js | 5 ++++ test/executor.test.js | 5 ++++ test/fixtures/browser-app-2/app.js | 5 ++++ test/fixtures/browser-app-2/models/robot.js | 5 ++++ test/fixtures/browser-app/app.js | 5 ++++ test/fixtures/browser-app/boot/configure.js | 5 ++++ .../browser-app/components/dummy-component.js | 5 ++++ .../browser-app/mixins/time-stamps.js | 5 ++++ test/fixtures/browser-app/models/customer.js | 5 ++++ test/fixtures/env-app/boot/test/bar.js | 5 ++++ test/fixtures/passport.js | 5 ++++ test/fixtures/simple-app/boot/bar.js | 5 ++++ test/fixtures/simple-app/boot/barSync.js | 5 ++++ test/fixtures/simple-app/boot/booting.js | 5 ++++ test/fixtures/simple-app/boot/foo.js | 5 ++++ test/fixtures/simple-app/middleware/index.js | 5 ++++ .../node_modules/my-module/index.js | 5 ++++ test/fixtures/simple-component.js | 5 ++++ test/fixtures/simple-middleware.js | 5 ++++ test/helpers/appdir.js | 5 ++++ test/helpers/browser.js | 5 ++++ test/helpers/browserify.js | 5 ++++ test/helpers/push-name-middleware.js | 5 ++++ test/helpers/sandbox.js | 5 ++++ 34 files changed, 185 insertions(+), 9 deletions(-) create mode 100644 LICENSE delete mode 100644 LICENSE.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..63b1fed --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) IBM Corp. 2014,2016. All Rights Reserved. +Node module: loopback-boot +This project is licensed under the MIT License, full text below. + +-------- + +MIT license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index ca2e8c9..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) 2013-2015 StrongLoop, Inc and other contributors. - -loopback-boot uses a dual license model. - -You may use this library under the terms of the [MIT License][], -or under the terms of the [StrongLoop Subscription Agreement][]. - -[MIT License]: http://opensource.org/licenses/MIT -[StrongLoop Subscription Agreement]: http://strongloop.com/license diff --git a/browser.js b/browser.js index becbec6..98c66c7 100644 --- a/browser.js +++ b/browser.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var execute = require('./lib/executor'); /** diff --git a/index.js b/index.js index 4619e51..9ece35c 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var ConfigLoader = require('./lib/config-loader'); var compile = require('./lib/compiler'); var execute = require('./lib/executor'); diff --git a/lib/bundler.js b/lib/bundler.js index 52e0736..cb0552a 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var fs = require('fs'); var path = require('path'); var commondir = require('commondir'); diff --git a/lib/compiler.js b/lib/compiler.js index d9fee0f..c6d489c 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var assert = require('assert'); var cloneDeep = require('lodash').cloneDeep; var fs = require('fs'); diff --git a/lib/config-loader.js b/lib/config-loader.js index 3f2a5fc..8d8c451 100644 --- a/lib/config-loader.js +++ b/lib/config-loader.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var fs = require('fs'); var path = require('path'); var debug = require('debug')('loopback:boot:config-loader'); diff --git a/lib/executor.js b/lib/executor.js index c22e32e..4059618 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var assert = require('assert'); var semver = require('semver'); var debug = require('debug')('loopback:boot:executor'); diff --git a/test/browser.multiapp.test.js b/test/browser.multiapp.test.js index 759a9ed..bfcafd4 100644 --- a/test/browser.multiapp.test.js +++ b/test/browser.multiapp.test.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var boot = require('../'); var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox; var fs = require('fs'); diff --git a/test/browser.test.js b/test/browser.test.js index 753fcd9..d179aa5 100644 --- a/test/browser.test.js +++ b/test/browser.test.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var boot = require('../'); var exportBrowserifyToFile = require('./helpers/browserify').exportToSandbox; var fs = require('fs'); diff --git a/test/compiler.test.js b/test/compiler.test.js index eac294f..646d32b 100644 --- a/test/compiler.test.js +++ b/test/compiler.test.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var boot = require('../'); var fs = require('fs-extra'); var path = require('path'); diff --git a/test/executor.test.js b/test/executor.test.js index 1851395..e051510 100644 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var async = require('async'); var boot = require('../'); var path = require('path'); diff --git a/test/fixtures/browser-app-2/app.js b/test/fixtures/browser-app-2/app.js index 9905979..d6ba5d3 100644 --- a/test/fixtures/browser-app-2/app.js +++ b/test/fixtures/browser-app-2/app.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var loopback = require('loopback'); var boot = require('../../../'); diff --git a/test/fixtures/browser-app-2/models/robot.js b/test/fixtures/browser-app-2/models/robot.js index 545c357..64c7d9b 100644 --- a/test/fixtures/browser-app-2/models/robot.js +++ b/test/fixtures/browser-app-2/models/robot.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(Robot) { Robot.settings._customized = 'Robot'; Robot.base.settings._customized = 'Robot'; diff --git a/test/fixtures/browser-app/app.js b/test/fixtures/browser-app/app.js index 6a9b9cb..f2c4fb6 100644 --- a/test/fixtures/browser-app/app.js +++ b/test/fixtures/browser-app/app.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var loopback = require('loopback'); var boot = require('../../../'); diff --git a/test/fixtures/browser-app/boot/configure.js b/test/fixtures/browser-app/boot/configure.js index b159ba7..96bbc51 100644 --- a/test/fixtures/browser-app/boot/configure.js +++ b/test/fixtures/browser-app/boot/configure.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(app) { app.set('custom-key', 'custom-value'); }; diff --git a/test/fixtures/browser-app/components/dummy-component.js b/test/fixtures/browser-app/components/dummy-component.js index 795a7a9..4a0da4b 100644 --- a/test/fixtures/browser-app/components/dummy-component.js +++ b/test/fixtures/browser-app/components/dummy-component.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(app, options) { app.dummyComponentOptions = options; }; diff --git a/test/fixtures/browser-app/mixins/time-stamps.js b/test/fixtures/browser-app/mixins/time-stamps.js index 6ba0a1a..0ca7ca5 100644 --- a/test/fixtures/browser-app/mixins/time-stamps.js +++ b/test/fixtures/browser-app/mixins/time-stamps.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(Model, options) { Model.timeStampsMixin = true; }; diff --git a/test/fixtures/browser-app/models/customer.js b/test/fixtures/browser-app/models/customer.js index 79a512d..9e0a0b3 100644 --- a/test/fixtures/browser-app/models/customer.js +++ b/test/fixtures/browser-app/models/customer.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(Customer) { Customer.settings._customized = 'Customer'; Customer.base.settings._customized = 'Base'; diff --git a/test/fixtures/env-app/boot/test/bar.js b/test/fixtures/env-app/boot/test/bar.js index d2a1f2f..68316c9 100644 --- a/test/fixtures/env-app/boot/test/bar.js +++ b/test/fixtures/env-app/boot/test/bar.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + process.bootFlags.push('barLoadedInTest'); module.exports = function(app, callback) { callback(); diff --git a/test/fixtures/passport.js b/test/fixtures/passport.js index 35e7060..d1833f2 100644 --- a/test/fixtures/passport.js +++ b/test/fixtures/passport.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var framework = { initialize: function(passport) { return function(req, res, next) { diff --git a/test/fixtures/simple-app/boot/bar.js b/test/fixtures/simple-app/boot/bar.js index 4e732a1..f726ea3 100644 --- a/test/fixtures/simple-app/boot/bar.js +++ b/test/fixtures/simple-app/boot/bar.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + process.bootFlags.push('barLoaded'); module.exports = function(app, callback) { process.bootFlags.push('barStarted'); diff --git a/test/fixtures/simple-app/boot/barSync.js b/test/fixtures/simple-app/boot/barSync.js index 4a38f80..7aca641 100644 --- a/test/fixtures/simple-app/boot/barSync.js +++ b/test/fixtures/simple-app/boot/barSync.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + process.bootFlags.push('barSyncLoaded'); module.exports = function(app) { process.bootFlags.push('barSyncExecuted'); diff --git a/test/fixtures/simple-app/boot/booting.js b/test/fixtures/simple-app/boot/booting.js index b7ec8b8..74f7031 100644 --- a/test/fixtures/simple-app/boot/booting.js +++ b/test/fixtures/simple-app/boot/booting.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(app, cb) { if (app.booting) process.bootingFlagSet = true; diff --git a/test/fixtures/simple-app/boot/foo.js b/test/fixtures/simple-app/boot/foo.js index e2fd7a5..9add48f 100644 --- a/test/fixtures/simple-app/boot/foo.js +++ b/test/fixtures/simple-app/boot/foo.js @@ -1 +1,6 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + process.bootFlags.push('fooLoaded'); diff --git a/test/fixtures/simple-app/middleware/index.js b/test/fixtures/simple-app/middleware/index.js index d2b20d9..df0110d 100644 --- a/test/fixtures/simple-app/middleware/index.js +++ b/test/fixtures/simple-app/middleware/index.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + exports.myMiddleware = function(name) { return function(req, res, next) { req._names = req._names || []; diff --git a/test/fixtures/simple-app/node_modules/my-module/index.js b/test/fixtures/simple-app/node_modules/my-module/index.js index 5b64f75..3ee16e1 100644 --- a/test/fixtures/simple-app/node_modules/my-module/index.js +++ b/test/fixtures/simple-app/node_modules/my-module/index.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + /** * Exporting a middleware as a property of the main module */ diff --git a/test/fixtures/simple-component.js b/test/fixtures/simple-component.js index a09da14..b15b827 100644 --- a/test/fixtures/simple-component.js +++ b/test/fixtures/simple-component.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(loopbackApp, params) { loopbackApp.use('/component', function(req, res, next) { res.send(params); diff --git a/test/fixtures/simple-middleware.js b/test/fixtures/simple-middleware.js index 30079f6..aec19a8 100644 --- a/test/fixtures/simple-middleware.js +++ b/test/fixtures/simple-middleware.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(params) { return function(req, res, next) { res.send(params); diff --git a/test/helpers/appdir.js b/test/helpers/appdir.js index a8955a6..cf1e67f 100644 --- a/test/helpers/appdir.js +++ b/test/helpers/appdir.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var path = require('path'); var fs = require('fs-extra'); var extend = require('util')._extend; diff --git a/test/helpers/browser.js b/test/helpers/browser.js index bbcd0f2..dc21615 100644 --- a/test/helpers/browser.js +++ b/test/helpers/browser.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015,2016. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var vm = require('vm'); function createContext() { diff --git a/test/helpers/browserify.js b/test/helpers/browserify.js index 02e1fbe..aac32d8 100644 --- a/test/helpers/browserify.js +++ b/test/helpers/browserify.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2015. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var fs = require('fs'); var sandbox = require('./sandbox'); diff --git a/test/helpers/push-name-middleware.js b/test/helpers/push-name-middleware.js index f7e6d6c..e11a1bd 100644 --- a/test/helpers/push-name-middleware.js +++ b/test/helpers/push-name-middleware.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + module.exports = function(name) { return function(req, res, next) { req._names = req._names || []; diff --git a/test/helpers/sandbox.js b/test/helpers/sandbox.js index cdd35bd..9afe701 100644 --- a/test/helpers/sandbox.js +++ b/test/helpers/sandbox.js @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2014. All Rights Reserved. +// Node module: loopback-boot +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + var fs = require('fs-extra'); var path = require('path'); From 58d932219075d2c709291f57029570728fb947de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Mon, 20 Jun 2016 17:11:43 +0200 Subject: [PATCH 10/10] 2.19.0 * update copyright notices and license (Ryan Graham) * Add flag var lazyConnect to ds config (juehou) --- CHANGES.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 674e3a6..334eb67 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +2016-06-20, Version 2.19.0 +========================== + + * update copyright notices and license (Ryan Graham) + + * Add flag var lazyConnect to ds config (juehou) + + 2016-04-13, Version 2.18.1 ========================== diff --git a/package.json b/package.json index b141228..64591ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-boot", - "version": "2.18.1", + "version": "2.19.0", "description": "Convention-based bootstrapper for LoopBack applications", "keywords": [ "StrongLoop",