diff --git a/lib/services.js b/lib/services.js index 2c36624..da72a78 100644 --- a/lib/services.js +++ b/lib/services.js @@ -54,6 +54,9 @@ module.exports = function generateServices(app, options) { options = extend({ ngModuleName: 'lbServices', apiUrl: '/', + includeCommonModules: true, + namespaceModels: false, + namespaceDelimiter: '.', }, options); var models = describeModels(app, options); @@ -67,13 +70,26 @@ module.exports = function generateServices(app, options) { moduleName: options.ngModuleName, models: models, urlBase: options.apiUrl.replace(/\/+$/, ''), + includeCommonModules: options.includeCommonModules, }); }; +function getFormattedModelName(modelName, options) { + // Always capitalize first letter of model name + var resourceModelName = modelName[0].toUpperCase() + modelName.slice(1); + + // Prefix with the module name and delimiter if namespacing is on + if (options.namespaceModels) { + resourceModelName = options.ngModuleName + + options.namespaceDelimiter + resourceModelName; + } + return resourceModelName; +} + function describeModels(app, options) { var result = {}; app.handler('rest').adapter.getClasses().forEach(function(c) { - var name = c.name; + var name = getFormattedModelName(c.name, options); c.description = c.sharedClass.ctor.settings.description; if (!c.ctor) { diff --git a/lib/services.template.ejs b/lib/services.template.ejs index c386d8e..eaada72 100644 --- a/lib/services.template.ejs +++ b/lib/services.template.ejs @@ -37,8 +37,6 @@ if (typeof module !== 'undefined' && typeof exports !== 'undefined' && <% for (var modelName in models) { var meta = models[modelName]; - // capitalize the model name - modelName = modelName[0].toUpperCase() + modelName.slice(1); -%> /** * @ngdoc object @@ -300,7 +298,7 @@ if (typeof module !== 'undefined' && typeof exports !== 'undefined' && }]); <% } // for modelName in models -%> - +<% if (includeCommonModules) { %> module .factory('LoopBackAuth', function() { var props = ['accessTokenId', 'currentUserId', 'rememberMe']; @@ -490,7 +488,8 @@ if (typeof module !== 'undefined' && typeof exports !== 'undefined' && return LoopBackResource; }]; }); -<% +<% } // end if (includeCommonModules) + function getJsDocType(arg) { var type = arg.type == 'any' ? '*' : arg.type; if (!arg.required) type += '='; diff --git a/test.e2e/given.js b/test.e2e/given.js index 7312c8f..28c7a61 100644 --- a/test.e2e/given.js +++ b/test.e2e/given.js @@ -58,7 +58,9 @@ define(['angular', 'angularMocks', 'angularResource'], function(angular) { * ``` */ given.servicesForLoopBackApp = function(options, cb) { - options.name = generateUniqueServiceName(options.name); + if (!options.name) { + options.name = generateUniqueServiceName(options.name); + } var promise = callSetup(options) .then(function(config) { return config.servicesUrl; }) diff --git a/test.e2e/spec/services.spec.js b/test.e2e/spec/services.spec.js index 194b163..d076c4a 100644 --- a/test.e2e/spec/services.spec.js +++ b/test.e2e/spec/services.spec.js @@ -1044,6 +1044,150 @@ define(['angular', 'given', 'util'], function(angular, given, util) { }); }); + describe('$resource generated with includeCommonModules:false', function() { + var $injector; + before(function() { + return given.servicesForLoopBackApp( + { + models: { + Product: { + properties: { + name: 'string', + price: { type: 'number' }, + }, + }, + }, + includeCommonModules: false, + }) + .then(function(createInjector) { + $injector = createInjector(); + }); + }); + + it('does not have "LoopBackAuth module"', function() { + expect(function() { + $injector.get('LoopBackAuth'); + }).to.throw(/Unknown provider/); + }); + + it('does not have "LoopBackResource provider"', function() { + expect(function() { + $injector.get('LoopBackResource'); + }).to.throw(/Unknown provider/); + }); + + it('does not have "LoopBackAuthRequestInterceptor module"', + function() { + expect(function() { + $injector.get('LoopBackAuthRequestInterceptor'); + }).to.throw(/Unknown provider/); + }); + }); + + describe('$resource generated with includeCommonModules:true (by default)', + function() { + var $injector; + before(function() { + return given.servicesForLoopBackApp( + { + models: { + Product: { + properties: { + name: 'string', + price: { type: 'number' }, + }, + }, + }, + }) + .then(function(createInjector) { + $injector = createInjector(); + }); + }); + + it('has "LoopBackAuth module"', function() { + expect(function() { + $injector.get('LoopBackAuth'); + }).to.not.throw(); + }); + + it('has "LoopBackResource provider"', function() { + expect(function() { + $injector.get('LoopBackResource'); + }).to.not.throw(); + }); + + it('has "LoopBackAuthRequestInterceptor module"', + function() { + expect(function() { + $injector.get('LoopBackAuthRequestInterceptor'); + }).to.not.throw(); + }); + }); + + describe('$resource generated with namespaceModels:true', function() { + var $injector; + before(function() { + return given.servicesForLoopBackApp( + { + models: { + Product: { + properties: { + name: 'string', + price: { type: 'number' }, + }, + }, + }, + name: 'lbServices', + namespaceModels: true, + }) + .then(function(createInjector) { + $injector = createInjector(); + }); + }); + + it('defines the "Product" model as "lbServices.Product"', function() { + expect(function() { + $injector.get('Product'); + }).to.throw(/Unknown provider/); + expect(function() { + $injector.get('lbServices.Product'); + }).to.not.throw(); + }); + }); + + describe('$resource generated with namespaceModels:true and ' + + 'namespaceDelimiter:_', function() { + var $injector; + before(function() { + return given.servicesForLoopBackApp( + { + models: { + Product: { + properties: { + name: 'string', + price: { type: 'number' }, + }, + }, + }, + name: 'lbServices', + namespaceModels: true, + namespaceDelimiter: '_', + }) + .then(function(createInjector) { + $injector = createInjector(); + }); + }); + + it('defines the "Product" model as "lbServices.Product"', function() { + expect(function() { + $injector.get('Product'); + }).to.throw(/Unknown provider/); + expect(function() { + $injector.get('lbServices_Product'); + }).to.not.throw(); + }); + }); + describe('for models with belongsTo relation', function() { var $injector, Town, Country, testData; before(function() { diff --git a/test.e2e/test-server.js b/test.e2e/test-server.js index 0b74ea6..ddc7cb3 100644 --- a/test.e2e/test-server.js +++ b/test.e2e/test-server.js @@ -67,7 +67,6 @@ masterApp.post('/setup', function(req, res, next) { var name = opts.name; var models = opts.models; var enableAuth = opts.enableAuth; - var includeSchema = opts.includeSchema; var setupFn = compileSetupFn(name, opts.setupFn); if (!name) @@ -105,19 +104,8 @@ masterApp.post('/setup', function(req, res, next) { res.send(500, err); return; } - try { - if (includeSchema) { - // the new options-based API - servicesScript = generator.services(lbApp, { - ngModuleName: name, - apiUrl: apiUrl, - includeSchema: includeSchema, - }); - } else { - // the old API, test it to verify backwards compatibility - servicesScript = generator.services(lbApp, name, apiUrl); - } + servicesScript = generateService(generator, lbApp, apiUrl, opts); } catch (err) { console.error('Cannot generate services script:', err.stack); servicesScript = 'throw new Error("Error generating services script.");'; @@ -161,6 +149,28 @@ masterApp.listen(port, function() { runAndExit(process.argv[2], process.argv.slice(3)); }); +function generateService(generator, lbApp, apiUrl, opts) { + var servicesScript; + if (opts.includeSchema !== undefined || + opts.includeCommonModules !== undefined || + opts.namespaceModels !== undefined || + opts.namespaceDelimiter !== undefined) { + // the new options-based API + + // build options object for new options-based API + var generatorOptions = opts; + generatorOptions.ngModuleName = opts.name; + generatorOptions.apiUrl = apiUrl; + + servicesScript = generator.services(lbApp, generatorOptions); + } else { + // the old API, test it to verify backwards compatibility + servicesScript = generator.services(lbApp, opts.name, apiUrl); + } + + return servicesScript; +} + function runAndExit(cmd, args) { console.log('Running %s %s', cmd, args.join(' ')); var child = require('child_process').spawn(cmd, args, { stdio: 'inherit' });