Skip to content

Commit

Permalink
Add new "no-old-shims" rule (#90)
Browse files Browse the repository at this point in the history
* Add "ember-rfc176-data" dependency

* Add new "no-old-shims" rule

* Make "no-old-shims" rule fixable

* Add documentation for "no-old-shims" rule
  • Loading branch information
Turbo87 authored and michalsnik committed Jul 10, 2017
1 parent d015c68 commit a864868
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ All rules from this plugin have to be prefixed with `ember/`
* General
* **local-modules** - Create local version of Ember.* and DS.* [(more)](https:/netguru/eslint-plugin-ember/blob/master/docs/RULES.md#create-local-version-of-ember-and-ds)
* **no-observers** - Don't use observers [(more)](https:/netguru/eslint-plugin-ember/blob/master/docs/RULES.md#dont-use-observers)
* **no-old-shims** - Don't use import paths from `ember-cli-shims` [(more)](https:/netguru/eslint-plugin-ember/blob/master/docs/rules/no-old-shims.md)
* **no-side-effects** - Don't introduce side-effects in computed properties [(more)](https:/netguru/eslint-plugin-ember/blob/master/docs/RULES.md#dont-introduce-side-effects-in-computed-properties)
* **jquery-ember-run** - Don’t use jQuery without Ember Run Loop [(more)](https:/netguru/eslint-plugin-ember/blob/master/docs/RULES.md#dont-use-jquery-without-ember-run-loop)
* **named-functions-in-promises** - Use named functions defined on objects to handle promises [(more)](https:/netguru/eslint-plugin-ember/blob/master/docs/RULES.md#use-named-functions-defined-on-objects-to-handle-promises)
Expand Down Expand Up @@ -114,6 +115,7 @@ All rules from this plugin have to be prefixed with `ember/`
"ember/no-empty-attrs": 0,
"ember/no-function-prototype-extensions": 0,
"ember/no-observers": 0,
"ember/no-old-shims": 0,
"ember/no-on-calls-in-components": 0,
"ember/no-side-effects": 0,
"ember/order-in-components": 0,
Expand Down
1 change: 1 addition & 0 deletions docs/RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* [`local-modules`](./rules/local-modules.md)
* [`jquery-ember-run`](./rules/jquery-ember-run.md)
* [`no-observers`](./rules/no-observers.md)
* [`no-old-shims`](./rules/no-old-shims.md)
* [`no-side-effects`](./rules/no-side-effects.md)
* [`named-functions-in-promises`](./rules/named-functions-in-promises.md)
* [`no-function-prototype-extensions`](./rules/no-function-prototype-extensions.md)
Expand Down
23 changes: 23 additions & 0 deletions docs/rules/no-old-shims.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Don't use import paths from `ember-cli-shims`

### Rule name: `no-old-shims`

The import paths in `ember-cli-shims` were never considered public API and
were recently replaced by [RFC #176](https:/emberjs/rfcs/pull/176).
If you use `ember-cli-babel` with version `6.6.0` or above you can start using
the "New Module Imports" instead of the old shims or the `Ember` global directly.
This will enable us to build better tree shaking feature into Ember CLI.

```javascript
// GOOD
import Component from '@ember/component'
import EmberObject, { computed } from '@ember/object'
import Service, { inject } from '@ember/service'

// BAD
import Component from 'ember-component';
import EmberObject from 'ember-object';
import computed from 'ember-computed';
import Service from 'ember-service';
import inject from 'ember-service/inject';
```
80 changes: 80 additions & 0 deletions lib/rules/no-old-shims.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use strict';

const oldShimsData = require('ember-rfc176-data/old-shims.json');

//------------------------------------------------------------------------------
// General rule - Don't use import paths from ember-cli-shims
//------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {},
fixable: 'code',
},

create(context) {
const message = 'Don\'t use import paths from ember-cli-shims';

return {
ImportDeclaration(node) {
const moduleName = node.source.value;
if (!(moduleName in oldShimsData)) {
return;
}

const moduleMappings = oldShimsData[moduleName];

const fix = function (fixer) {
const newImports = {};

node.specifiers.forEach((specifier) => {
const localName = specifier.local.name;

let importedName;
if (specifier.type === 'ImportDefaultSpecifier') {
importedName = 'default';
} else {
importedName = specifier.imported.name;
}

let module;
const moduleMapping = moduleMappings[importedName];
if (!moduleMapping) {
module = moduleName;
} else {
module = moduleMapping[0];
importedName = moduleMapping[1] || 'default';
}

newImports[module] = newImports[module] || [];
newImports[module].push({ localName, importedName });
});

const lines = Object.keys(newImports).map((module) => {
const newModuleImport = newImports[module];

const defaultImport = newModuleImport
.filter(it => it.importedName === 'default')
.map(it => it.localName);

const namedImports = newModuleImport
.filter(it => it.importedName !== 'default')
.map(it => (it.importedName !== it.localName ? `${it.importedName} as ${it.localName}` : it.importedName))
.join(', ');

const specifiers = defaultImport
.concat(namedImports ? `{ ${namedImports} }` : '')
.filter(Boolean)
.join(', ');

return `import ${specifiers} from '${module}';`;
});

return fixer.replaceText(node, lines.join('\n'));
};

context.report({ node, message, fix });
},
};
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"jest": "^20.0.4"
},
"dependencies": {
"ember-rfc176-data": "^0.2.2",
"requireindex": "^1.1.0",
"snake-case": "^2.1.0"
},
Expand Down
71 changes: 71 additions & 0 deletions tests/lib/rules/no-old-shims.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const rule = require('../../../lib/rules/no-old-shims');
const RuleTester = require('eslint').RuleTester;

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

const eslintTester = new RuleTester();
eslintTester.run('no-old-shims', rule, {
valid: [
{
code: 'import Ember from \'ember\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
{
code: 'import RSVP from \'rsvp\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
],
invalid: [
{
code: 'import Component from \'ember-component\';',
output: 'import Component from \'@ember/component\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{ message: 'Don\'t use import paths from ember-cli-shims' }],
},
{
code: 'import { capitalize, dasherize, foo } from \'ember-string\';',
output: 'import { capitalize, dasherize } from \'@ember/string\';\nimport { foo } from \'ember-string\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{ message: 'Don\'t use import paths from ember-cli-shims' }],
},
{
code: 'import computed, { not } from \'ember-computed\';',
output: 'import { computed } from \'@ember/object\';\nimport { not } from \'@ember/object/computed\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{ message: 'Don\'t use import paths from ember-cli-shims' }],
},
{
code: 'import { log } from \'ember-debug\';',
output: 'import { debug as log } from \'@ember/debug\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{ message: 'Don\'t use import paths from ember-cli-shims' }],
},
{
code: 'import { log as debug } from \'ember-debug\';',
output: 'import { debug } from \'@ember/debug\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{ message: 'Don\'t use import paths from ember-cli-shims' }],
},
{
code: 'import Sortable from \'ember-controllers/sortable\';',
output: 'import Sortable from \'ember-controllers/sortable\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [{ message: 'Don\'t use import paths from ember-cli-shims' }],
},
{
code: 'import Service from \'ember-service\';\nimport inject from \'ember-service/inject\';',
output: 'import Service from \'@ember/service\';\nimport { inject } from \'@ember/service\';',
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
errors: [
{ message: 'Don\'t use import paths from ember-cli-shims' },
{ message: 'Don\'t use import paths from ember-cli-shims' },
],
},
],
});
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,10 @@ ecc-jsbn@~0.1.1:
dependencies:
jsbn "~0.1.0"

ember-rfc176-data@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.2.2.tgz#cbe0896cd7855d6cc58d809d5616ea0d523b009e"

errno@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
Expand Down

0 comments on commit a864868

Please sign in to comment.