Skip to content

Commit

Permalink
Only extend from application serializer / adapter, if it exists
Browse files Browse the repository at this point in the history
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();
```
  • Loading branch information
pangratz committed Apr 6, 2016
1 parent 8959c4e commit b6c2c7c
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 36 deletions.
33 changes: 2 additions & 31 deletions blueprints/adapter/index.js
Original file line number Diff line number Diff line change
@@ -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.',
Expand All @@ -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);
}
};
4 changes: 2 additions & 2 deletions blueprints/serializer/files/__root__/__path__/__name__.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import JSONAPISerializer from 'ember-data/serializers/json-api';
<%= importStatement %>

export default JSONAPISerializer.extend({
export default <%= baseClass %>.extend({
});
12 changes: 11 additions & 1 deletion blueprints/serializer/index.js
Original file line number Diff line number Diff line change
@@ -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);
}
};
40 changes: 40 additions & 0 deletions lib/utilities/extend-from-application-entity.js
Original file line number Diff line number Diff line change
@@ -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
};
};
29 changes: 27 additions & 2 deletions node-tests/blueprints/adapter-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({'
]
},
{
Expand All @@ -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: [
Expand Down
74 changes: 74 additions & 0 deletions node-tests/blueprints/serializer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down

0 comments on commit b6c2c7c

Please sign in to comment.