Skip to content

Commit 67722ea

Browse files
committed
feat(generate): add ability to specify module for import
Closes angular#3806
1 parent 2a513ca commit 67722ea

File tree

15 files changed

+210
-25
lines changed

15 files changed

+210
-25
lines changed

packages/angular-cli/blueprints/component/index.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const path = require('path');
2+
const fs = require('fs');
23
const chalk = require('chalk');
34
const Blueprint = require('../../ember-cli/lib/models/blueprint');
45
const dynamicPathParser = require('../../utilities/dynamic-path-parser');
@@ -19,15 +20,27 @@ module.exports = {
1920
{ name: 'spec', type: Boolean },
2021
{ name: 'view-encapsulation', type: String, aliases: ['ve'] },
2122
{ name: 'change-detection', type: String, aliases: ['cd'] },
22-
{ name: 'skip-import', type: Boolean, default: false }
23+
{ name: 'skip-import', type: Boolean, default: false },
24+
{ name: 'module', type: String, aliases: ['m'] }
2325
],
2426

2527
beforeInstall: function(options) {
26-
try {
27-
this.pathToModule = findParentModule(this.project, this.dynamicPath.dir);
28-
} catch(e) {
29-
if (!options.skipImport) {
30-
throw `Error locating module for declaration\n\t${e}`;
28+
if (options.module) {
29+
// Resolve path to module
30+
const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`;
31+
const parsedPath = dynamicPathParser(this.project, modulePath);
32+
this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base);
33+
34+
if (!fs.existsSync(this.pathToModule)) {
35+
throw `Module specified does not exist`;
36+
}
37+
} else {
38+
try {
39+
this.pathToModule = findParentModule(this.project, this.dynamicPath.dir);
40+
} catch(e) {
41+
if (!options.skipImport) {
42+
throw `Error locating module for declaration\n\t${e}`;
43+
}
3144
}
3245
}
3346
},

packages/angular-cli/blueprints/directive/index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,27 @@ module.exports = {
1515
{ name: 'flat', type: Boolean, default: true },
1616
{ name: 'prefix', type: String, default: null },
1717
{ name: 'spec', type: Boolean },
18-
{ name: 'skip-import', type: Boolean, default: false }
18+
{ name: 'skip-import', type: Boolean, default: false },
19+
{ name: 'module', type: String, aliases: ['m'] }
1920
],
2021

2122
beforeInstall: function(options) {
22-
try {
23-
this.pathToModule = findParentModule(this.project, this.dynamicPath.dir);
24-
} catch(e) {
25-
if (!options.skipImport) {
26-
throw `Error locating module for declaration\n\t${e}`;
23+
if (options.module) {
24+
// Resolve path to module
25+
const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`;
26+
const parsedPath = dynamicPathParser(this.project, modulePath);
27+
this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base);
28+
29+
if (!fs.existsSync(this.pathToModule)) {
30+
throw `Module specified does not exist`;
31+
}
32+
} else {
33+
try {
34+
this.pathToModule = findParentModule(this.project, this.dynamicPath.dir);
35+
} catch(e) {
36+
if (!options.skipImport) {
37+
throw `Error locating module for declaration\n\t${e}`;
38+
}
2739
}
2840
}
2941
},

packages/angular-cli/blueprints/pipe/index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,27 @@ module.exports = {
1414
availableOptions: [
1515
{ name: 'flat', type: Boolean, default: true },
1616
{ name: 'spec', type: Boolean },
17-
{ name: 'skip-import', type: Boolean, default: false }
17+
{ name: 'skip-import', type: Boolean, default: false },
18+
{ name: 'module', type: String, aliases: ['m'] }
1819
],
1920

2021
beforeInstall: function(options) {
21-
try {
22-
this.pathToModule = findParentModule(this.project, this.dynamicPath.dir);
23-
} catch(e) {
24-
if (!options.skipImport) {
25-
throw `Error locating module for declaration\n\t${e}`;
22+
if (options.module) {
23+
// Resolve path to module
24+
const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`;
25+
const parsedPath = dynamicPathParser(this.project, modulePath);
26+
this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base);
27+
28+
if (!fs.existsSync(this.pathToModule)) {
29+
throw `Module specified does not exist`;
30+
}
31+
} else {
32+
try {
33+
this.pathToModule = findParentModule(this.project, this.dynamicPath.dir);
34+
} catch(e) {
35+
if (!options.skipImport) {
36+
throw `Error locating module for declaration\n\t${e}`;
37+
}
2638
}
2739
}
2840
},

packages/angular-cli/blueprints/service/index.js

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,32 @@ const path = require('path');
22
const chalk = require('chalk');
33
const dynamicPathParser = require('../../utilities/dynamic-path-parser');
44
const Blueprint = require('../../ember-cli/lib/models/blueprint');
5+
const stringUtils = require('ember-cli-string-utils');
6+
const astUtils = require('../../utilities/ast-utils');
57
const getFiles = Blueprint.prototype.files;
68

79
module.exports = {
810
description: '',
911

1012
availableOptions: [
1113
{ name: 'flat', type: Boolean, default: true },
12-
{ name: 'spec', type: Boolean }
14+
{ name: 'spec', type: Boolean },
15+
{ name: 'module', type: String, aliases: ['m'] }
1316
],
1417

18+
beforeInstall: function(options) {
19+
if (options.module) {
20+
// Resolve path to module
21+
const modulePath = options.module.endsWith('.ts') ? options.module : `${options.module}.ts`;
22+
const parsedPath = dynamicPathParser(this.project, modulePath);
23+
this.pathToModule = path.join(this.project.root, parsedPath.dir, parsedPath.base);
24+
25+
if (!fs.existsSync(this.pathToModule)) {
26+
throw `Module specified does not exist`;
27+
}
28+
}
29+
},
30+
1531
normalizeEntityName: function (entityName) {
1632
var parsedPath = dynamicPathParser(this.project, entityName);
1733

@@ -55,7 +71,25 @@ module.exports = {
5571
},
5672

5773
afterInstall() {
58-
const warningMessage = 'Service is generated but not provided, it must be provided to be used';
59-
this._writeStatusToUI(chalk.yellow, 'WARNING', warningMessage);
74+
const returns = [];
75+
const className = stringUtils.classify(`${options.entity.name}Service`);
76+
const fileName = stringUtils.dasherize(`${options.entity.name}.service`);
77+
const fullGeneratePath = path.join(this.project.root, this.generatePath);
78+
const moduleDir = path.parse(this.pathToModule).dir;
79+
const relativeDir = path.relative(moduleDir, fullGeneratePath);
80+
const importPath = relativeDir ? `./${relativeDir}/${fileName}` : `./${fileName}`;
81+
82+
if (!this.pathToModule) {
83+
const warningMessage = 'Service is generated but not provided, it must be provided to be used';
84+
this._writeStatusToUI(chalk.yellow, 'WARNING', warningMessage);
85+
} else {
86+
returns.push(
87+
astUtils.addProviderToModule(this.pathToModule, className, importPath)
88+
.then(change => change.apply(NodeHost)));
89+
//modulePath: string, classifiedName: string, importPath: string
90+
this._writeStatusToUI(chalk.yellow, 'update', path.relative(this.project.root, this.pathToModule));
91+
}
92+
93+
return Promise.all(returns);
6094
}
6195
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {ng} from '../../../utils/process';
2+
import {expectToFail} from '../../../utils/utils';
3+
4+
5+
export default function() {
6+
return Promise.resolve()
7+
.then(() => expectToFail(() =>
8+
ng('generate', 'component', 'test-component', '-m app.moduleXXX.ts')));
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {join} from 'path';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToMatch} from '../../../utils/fs';
4+
5+
6+
export default function() {
7+
const modulePath = join('src', 'app', 'app.module.ts');
8+
9+
return ng('generate', 'component', 'test-component', '-m app.module.ts')
10+
.then(() => expectFileToMatch(modulePath,
11+
/import { TestComponent } from '.\/test-component\/test-component.component'/))
12+
13+
// Try to run the unit tests.
14+
.then(() => ng('test', '--single-run'));
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {join} from 'path';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToExist} from '../../../utils/fs';
4+
5+
6+
export default function() {
7+
const directiveDir = join('src', 'app', 'test-directive');
8+
9+
return ng('generate', 'directive', 'test-directive')
10+
.then(() => expectFileToExist(directiveDir))
11+
.then(() => expectFileToExist(join(directiveDir, 'test-directive.directive.ts')))
12+
.then(() => expectFileToExist(join(directiveDir, 'test-directive.directive.spec.ts')))
13+
.then(() => expectFileToExist(join(directiveDir, 'test-directive.directive.html')))
14+
.then(() => expectFileToExist(join(directiveDir, 'test-directive.directive.css')))
15+
16+
// Try to run the unit tests.
17+
.then(() => ng('test', '--single-run'));
18+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {ng} from '../../../utils/process';
2+
import {expectToFail} from '../../../utils/utils';
3+
4+
5+
export default function() {
6+
return Promise.resolve()
7+
.then(() => expectToFail(() =>
8+
ng('generate', 'directive', 'test-directive', '-m app.moduleXXX.ts')));
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {join} from 'path';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToMatch} from '../../../utils/fs';
4+
5+
6+
export default function() {
7+
const modulePath = join('src', 'app', 'app.module.ts');
8+
9+
return ng('generate', 'directive', 'test-directive', '-m app.module.ts')
10+
.then(() => expectFileToMatch(modulePath,
11+
/import { TestDirective } from '.\/test-directive\/test-directive.directive'/))
12+
13+
// Try to run the unit tests.
14+
.then(() => ng('test', '--single-run'));
15+
}

tests/e2e/tests/generate/pipe.ts renamed to tests/e2e/tests/generate/pipe/pipe-basic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {join} from 'path';
2-
import {ng} from '../../utils/process';
3-
import {expectFileToExist} from '../../utils/fs';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToExist} from '../../../utils/fs';
44

55

66
export default function() {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {ng} from '../../../utils/process';
2+
import {expectToFail} from '../../../utils/utils';
3+
4+
5+
export default function() {
6+
return Promise.resolve()
7+
.then(() => expectToFail(() =>
8+
ng('generate', 'pipe', 'test-pipe', '-m app.moduleXXX.ts')));
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {join} from 'path';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToMatch} from '../../../utils/fs';
4+
5+
6+
export default function() {
7+
const modulePath = join('src', 'app', 'app.module.ts');
8+
9+
return ng('generate', 'pipe', 'test-pipe', '-m app.module.ts')
10+
.then(() => expectFileToMatch(modulePath,
11+
/import { TestPipe } from '.\/test-pipe\/test-pipe.pipe'/))
12+
13+
// Try to run the unit tests.
14+
.then(() => ng('test', '--single-run'));
15+
}

tests/e2e/tests/generate/service.ts renamed to tests/e2e/tests/generate/service/service-basic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {join} from 'path';
2-
import {ng} from '../../utils/process';
3-
import {expectFileToExist} from '../../utils/fs';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToExist} from '../../../utils/fs';
44

55

66
export default function() {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {ng} from '../../../utils/process';
2+
import {expectToFail} from '../../../utils/utils';
3+
4+
5+
export default function() {
6+
return Promise.resolve()
7+
.then(() => expectToFail(() =>
8+
ng('generate', 'service', 'test-service', '-m app.moduleXXX.ts')));
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {join} from 'path';
2+
import {ng} from '../../../utils/process';
3+
import {expectFileToMatch} from '../../../utils/fs';
4+
5+
6+
export default function() {
7+
const modulePath = join('src', 'app', 'app.module.ts');
8+
9+
return ng('generate', 'service', 'test-service', '-m app.module.ts')
10+
.then(() => expectFileToMatch(modulePath,
11+
/import { TestService } from '.\/test-service\/test-service.service'/))
12+
13+
// Try to run the unit tests.
14+
.then(() => ng('test', '--single-run'));
15+
}

0 commit comments

Comments
 (0)