diff --git a/CHANGES.md b/CHANGES.md index fc9612b..c073c14 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,9 @@ +2014-12-02, Version 2.5.0 +========================= + + * compiler: resolve paths in middleware params (Miroslav Bajtoš) + + 2014-11-27, Version 2.4.0 ========================= diff --git a/lib/compiler.js b/lib/compiler.js index 6cfd3ad..f8f058b 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -364,6 +364,11 @@ function buildMiddlewareInstructions(rootDir, config) { var middlewareConfig = cloneDeep(config); middlewareConfig.phase = phase; + if (middlewareConfig.params) { + middlewareConfig.params = resolveMiddlewareParams( + rootDir, middlewareConfig.params); + } + var item = { sourceFile: resolved.sourceFile, config: middlewareConfig @@ -448,3 +453,16 @@ function resolveMiddlewarePath(rootDir, middleware) { } throw err; } + +// Match values starting with `$!./` or `$!../` +var MIDDLEWARE_PATH_PARAM_REGEX = /^\$!(\.\/|\.\.\/)/; + +function resolveMiddlewareParams(rootDir, params) { + return cloneDeep(params, function resolvePathParam(value) { + if (typeof value === 'string' && MIDDLEWARE_PATH_PARAM_REGEX.test(value)) { + return path.resolve(rootDir, value.slice(2)); + } else { + return undefined; // no change + } + }); +} diff --git a/package.json b/package.json index a5b39c0..47a268c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-boot", - "version": "2.4.0", + "version": "2.5.0", "description": "Convention-based bootstrapper for LoopBack applications", "keywords": [ "StrongLoop", diff --git a/test/compiler.test.js b/test/compiler.test.js index a4f9a1d..edc128e 100644 --- a/test/compiler.test.js +++ b/test/compiler.test.js @@ -790,7 +790,7 @@ describe('compiler', function() { var instructions = boot.compile(appdir.PATH); - expect(instructions.middleware.middleware[0].config.params).to.eql({ + expectFirstMiddlewareParams(instructions).to.eql({ key: 'custom value' }); }); @@ -954,9 +954,93 @@ describe('compiler', function() { 'sourceFile', appdir.resolve(HANDLER_FILE)); }); + + describe('config with relative paths in params', function() { + var RELATIVE_PATH_PARAMS = [ + '$!./here', + '$!../there' + ]; + + var absolutePathParams; + beforeEach(function resolveRelativePathParams() { + absolutePathParams = RELATIVE_PATH_PARAMS.map(function(p) { + return appdir.resolve(p.slice(2)); + }); + }); + + it('converts paths in top-level array items', function() { + givenMiddlewareEntrySync({ params: RELATIVE_PATH_PARAMS }); + + var instructions = boot.compile(appdir.PATH); + + expectFirstMiddlewareParams(instructions) + .to.eql(absolutePathParams); + }); + + it('converts paths in top-level object properties', function() { + givenMiddlewareEntrySync({ params: { + path: RELATIVE_PATH_PARAMS[0], + }}); + + var instructions = boot.compile(appdir.PATH); + + expectFirstMiddlewareParams(instructions) + .to.eql({ path: absolutePathParams[0] }); + }); + + it('converts path value when params is a string', function() { + givenMiddlewareEntrySync({ params: RELATIVE_PATH_PARAMS[0] }); + + var instructions = boot.compile(appdir.PATH); + + expectFirstMiddlewareParams(instructions) + .to.eql(absolutePathParams[0]); + }); + + it('converts paths in nested properties', function() { + givenMiddlewareEntrySync({ params: { + nestedObject: { + path: RELATIVE_PATH_PARAMS[0] + }, + nestedArray: RELATIVE_PATH_PARAMS + }}); + + var instructions = boot.compile(appdir.PATH); + + expectFirstMiddlewareParams(instructions) + .to.eql({ + nestedObject: { + path: absolutePathParams[0] + }, + nestedArray: absolutePathParams + }); + }); + + it('does not convert values not starting with `./` or `../`', function() { + var PARAMS = ['$!.somerc', '$!/root', '$!hello!']; + givenMiddlewareEntrySync({ params: PARAMS}); + + var instructions = boot.compile(appdir.PATH); + + expectFirstMiddlewareParams(instructions).to.eql(PARAMS); + }); + }); }); }); function getNameProperty(obj) { return obj.name; } + +function givenMiddlewareEntrySync(config) { + appdir.writeConfigFileSync('middleware.json', { + initial: { + // resolves to ./middleware.json + './middleware': config + } + }); +} + +function expectFirstMiddlewareParams(instructions) { + return expect(instructions.middleware.middleware[0].config.params); +}