From b6c2c7c25dface19bb0ff9f78f36848f17284740 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 19 Jan 2016 14:41:51 +0100 Subject: [PATCH] Only extend from application serializer / adapter, if it exists This change updates the blueprints for adapter and serializer, so they extend from the application entity if it exists: If there is an application adapter - located in `app/adapters/application.js` - and the command `ember g adapter foo` is invoked, the created adapter extends from the application adapter: ```js // app/adapters/foo.js import ApplicationAdapter from './application'; export default ApplicationAdapter.extend(); ``` If there is no application entity, the JSONAPI equivalent is used. Consider no application serializer in `app/serializers/appliation.js` and the command `ember generate serializer foo` is invoked, then the created serializer extends from JSONAPISerializer: ```js // app/serializers/foo.js import JSONAPISerializer from 'ember-data/serializers/json-api'; export default JSONAPISerializer.extend(); ``` --- blueprints/adapter/index.js | 33 +-------- .../files/__root__/__path__/__name__.js | 4 +- blueprints/serializer/index.js | 12 ++- .../extend-from-application-entity.js | 40 ++++++++++ node-tests/blueprints/adapter-test.js | 29 +++++++- node-tests/blueprints/serializer-test.js | 74 +++++++++++++++++++ 6 files changed, 156 insertions(+), 36 deletions(-) create mode 100644 lib/utilities/extend-from-application-entity.js diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index b6a3416e381..9295dc6fd75 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -1,8 +1,6 @@ /*jshint node:true*/ -var stringUtil = require('ember-cli-string-utils'); -var SilentError = require('silent-error'); -var pathUtil = require('ember-cli-path-utils'); +var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); module.exports = { description: 'Generates an ember-data adapter.', @@ -12,33 +10,6 @@ module.exports = { ], locals: function(options) { - var adapterName = options.entity.name; - var baseClass = 'JSONAPIAdapter'; - var importStatement = 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';'; - var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); - var relativePath = pathUtil.getRelativePath(options.entity.name); - - if (options.pod && options.podPath) { - relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); - } - - if (!isAddon && !options.baseClass && adapterName !== 'application') { - options.baseClass = 'application'; - } - - if (options.baseClass === adapterName) { - throw new SilentError('Adapters cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); - } - - if (options.baseClass) { - baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); - baseClass = baseClass + 'Adapter'; - importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; - } - - return { - importStatement: importStatement, - baseClass: baseClass - }; + return extendFromApplicationEntity('adapter', 'JSONAPIAdapter', 'ember-data/adapters/json-api', options); } }; diff --git a/blueprints/serializer/files/__root__/__path__/__name__.js b/blueprints/serializer/files/__root__/__path__/__name__.js index 4678cc2c37a..2b54b829447 100644 --- a/blueprints/serializer/files/__root__/__path__/__name__.js +++ b/blueprints/serializer/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import JSONAPISerializer from 'ember-data/serializers/json-api'; +<%= importStatement %> -export default JSONAPISerializer.extend({ +export default <%= baseClass %>.extend({ }); diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index bd3f41c12cd..91b57db3976 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -1,5 +1,15 @@ /*jshint node:true*/ +var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); + module.exports = { - description: 'Generates an ember-data serializer.' + description: 'Generates an ember-data serializer.', + + availableOptions: [ + { name: 'base-class', type: String } + ], + + locals: function(options) { + return extendFromApplicationEntity('serializer', 'JSONAPISerializer', 'ember-data/serializers/json-api', options); + } }; diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js new file mode 100644 index 00000000000..cb340293364 --- /dev/null +++ b/lib/utilities/extend-from-application-entity.js @@ -0,0 +1,40 @@ +var stringUtil = require('ember-cli-string-utils'); +var SilentError = require('silent-error'); +var pathUtil = require('ember-cli-path-utils'); +var existsSync = require('exists-sync'); +var path = require('path'); + +module.exports = function(type, baseClass, packagePath, options) { + var entityName = options.entity.name; + var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); + var relativePath = pathUtil.getRelativePath(options.entity.name); + + if (options.pod && options.podPath) { + relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); + } + + var entityDirectory = type + 's'; + var applicationEntityPath = path.join(options.project.root, 'app', entityDirectory, 'application.js'); + var hasApplicationEntity = existsSync(applicationEntityPath); + if (!isAddon && !options.baseClass && entityName !== 'application' && hasApplicationEntity) { + options.baseClass = 'application'; + packagePath = './application'; + } + + if (options.baseClass === entityName) { + throw new SilentError(stringUtil.classify(type) + 's cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); + } + + var importStatement = 'import ' + baseClass + ' from \'' + packagePath + '\';'; + + if (options.baseClass) { + baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); + baseClass = baseClass + stringUtil.classify(type); + importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; + } + + return { + importStatement: importStatement, + baseClass: baseClass + }; +}; diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 074f3cc3079..74be00aa4e4 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -11,8 +11,8 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { { file: 'app/adapters/foo.js', contains: [ - 'import ApplicationAdapter from \'./application\';', - 'export default ApplicationAdapter.extend({' + 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';', + 'export default JSONAPIAdapter.extend({' ] }, { @@ -25,6 +25,31 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); + it('adapter extends application adapter if it exists', function() { + return generateAndDestroy(['adapter', 'application'], { + afterGenerate: function() { + return generateAndDestroy(['adapter', 'foo'], { + skipInit: true, + files: [ + { + file: 'app/adapters/foo.js', + contains: [ + 'import ApplicationAdapter from \'./application\';', + 'export default ApplicationAdapter.extend({' + ] + }, + { + file: 'tests/unit/adapters/foo-test.js', + contains: [ + 'moduleFor(\'adapter:foo\'' + ] + } + ] + }); + } + }); + }); + it('adapter with --base-class', function() { return generateAndDestroy(['adapter', 'foo', '--base-class=bar'], { files: [ diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 958eaa0e42a..b955f75f843 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -25,6 +25,80 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { }); }); + it('serializer extends application serializer if it exists', function() { + return generateAndDestroy(['serializer', 'application'], { + afterGenerate: function() { + return generateAndDestroy(['serializer', 'foo'], { + skipInit: true, + files: [ + { + file: 'app/serializers/foo.js', + contains: [ + 'import ApplicationSerializer from \'./application\';', + 'export default ApplicationSerializer.extend({' + ] + }, + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + } + }); + }); + + it('serializer with --base-class', function() { + return generateAndDestroy(['serializer', 'foo', '--base-class=bar'], { + files: [ + { + file: 'app/serializers/foo.js', + contains: [ + 'import BarSerializer from \'./bar\';', + 'export default BarSerializer.extend({' + ] + }, + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); + + it('serializer throws when --base-class is same as name', function() { + return generateAndDestroy(['serializer', 'application', '--base-class=application'], { + throws: { + message: /Serializers cannot extend from themself/, + type: 'SilentError' + } + }); + }); + + it('serializer when is named "application"', function() { + return generateAndDestroy(['serializer', 'application'], { + files: [ + { + file: 'app/serializers/application.js', + contains: [ + 'import JSONAPISerializer from \'ember-data/serializers/json-api\';', + 'export default JSONAPISerializer.extend({' + ] + }, + { + file: 'tests/unit/serializers/application-test.js', + contains: [ + 'moduleForModel(\'application\'' + ] + } + ] + }); + }); + it('serializer-test', function() { return generateAndDestroy(['serializer-test', 'foo'], { files: [