Skip to content

Commit 1dea1bf

Browse files
committed
feat(@angular/cli): make appRoot customizable
1 parent b79549d commit 1dea1bf

File tree

6 files changed

+77
-9
lines changed

6 files changed

+77
-9
lines changed

packages/@angular/cli/commands/generate.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,18 @@ export default Command.extend({
137137
dryRun: commandOptions.dryRun
138138
};
139139
const parsedPath = dynamicPathParser(dynamicPathOptions);
140-
const root = appConfig.root + path.sep;
141140
commandOptions.sourceDir = appConfig.root;
142-
commandOptions.appRoot = parsedPath.appRoot.startsWith(root)
143-
? parsedPath.appRoot.substr(root.length)
144-
: parsedPath.appRoot;
141+
const root = appConfig.root + path.sep;
142+
commandOptions.appRoot = parsedPath.appRoot === appConfig.root ? '' :
143+
parsedPath.appRoot.startsWith(root)
144+
? parsedPath.appRoot.substr(root.length)
145+
: parsedPath.appRoot;
146+
145147
commandOptions.path = parsedPath.dir.replace(separatorRegEx, '/');
146-
if (parsedPath.dir.startsWith(root)) {
147-
commandOptions.path = commandOptions.path.substr(root.length);
148-
}
148+
commandOptions.path = parsedPath.dir === appConfig.root ? '' :
149+
parsedPath.dir.startsWith(root)
150+
? commandOptions.path.substr(root.length)
151+
: commandOptions.path;
149152

150153
const cwd = this.project.root;
151154
const schematicName = rawArgs[0];

packages/@angular/cli/lib/config/schema.json

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
"type": "string",
3434
"description": "Name of the app."
3535
},
36+
"appRoot": {
37+
"type": "string",
38+
"description": "Directory where app files are placed.",
39+
"default": "app"
40+
},
3641
"root": {
3742
"type": "string",
3843
"description": "The root directory of the app."

packages/@angular/cli/utilities/dynamic-path-parser.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export interface DynamicPathOptions {
1313
export function dynamicPathParser(options: DynamicPathOptions) {
1414
const projectRoot = options.project.root;
1515
const sourceDir = options.appConfig.root;
16-
const appRoot = path.join(sourceDir, 'app');
16+
17+
const p = options.appConfig.appRoot === undefined ? 'app' : options.appConfig.appRoot;
18+
const appRoot = path.join(sourceDir, p);
1719
const cwd = process.env.PWD;
1820

1921
const rootPath = path.join(projectRoot, appRoot);

tests/acceptance/dynamic-path-parser.spec.ts

+26
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,32 @@ describe('dynamic path parser', () => {
5050
expect(result.name).toBe(entityName);
5151
});
5252

53+
it('respects the appRoot configuration', () => {
54+
process.env.PWD = project.root;
55+
const options = {
56+
project,
57+
entityName,
58+
appConfig: {...appConfig, appRoot: 'other'},
59+
dryRun: false
60+
};
61+
const result = dynamicPathParser(options);
62+
expect(result.dir).toBe(`src${path.sep}other`);
63+
expect(result.name).toBe(entityName);
64+
});
65+
66+
it('respects the empty appRoot configuration', () => {
67+
process.env.PWD = project.root;
68+
const options = {
69+
project,
70+
entityName,
71+
appConfig: <any>{...appConfig, appRoot: ''},
72+
dryRun: false
73+
};
74+
const result = dynamicPathParser(options);
75+
expect(result.dir).toBe(`src`);
76+
expect(result.name).toBe(entityName);
77+
});
78+
5379
it('parse from proj src dir', () => {
5480
process.env.PWD = path.join(project.root, 'src');
5581
const options = {

tests/acceptance/generate-component.spec.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// tslint:disable:max-line-length
2-
import { mkdirsSync, pathExistsSync, readFile, readFileSync } from 'fs-extra';
2+
import { mkdirsSync, pathExistsSync, readFile, readFileSync, writeFileSync } from 'fs-extra';
33
import * as path from 'path';
44
import { ng, setupProject } from '../helpers';
55

@@ -345,5 +345,22 @@ describe('Acceptance: ng generate component', () => {
345345
})
346346
.then(done, done.fail);
347347
});
348+
349+
describe('should generate components in apps with empty appRoot', () => {
350+
it('should work', (done) => {
351+
const appRoot = path.join(root, 'tmp/foo');
352+
mkdirsSync(path.join(appRoot, 'other', 'src'));
353+
354+
return ng(['generate', 'module', 'm', '--app', 'other']).then(() => {
355+
const expectedModule = path.join(appRoot, 'other', 'src', 'm', 'm.module.ts');
356+
expect(pathExistsSync(expectedModule)).toBe(true);
357+
358+
return ng(['generate', 'component', 'm/c', '--app', 'other', '--module', 'm']).then(() => {
359+
expect(pathExistsSync(path.join(appRoot, 'other', 'src', 'm', 'c', 'c.component.ts'))).toBe(true);
360+
expect(readFileSync(expectedModule, 'utf-8')).toContain(`import { CComponent } from './c/c.component'`);
361+
});
362+
}).then(done, done.fail);
363+
});
364+
});
348365
});
349366
});

tests/helpers/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import * as path from 'path';
2+
import {writeFile, readFile} from 'fs-extra';
3+
14
const ng: ((parameters: string[]) => Promise<any>) = require('./ng');
25
const tmp = require('./tmp');
36

@@ -8,6 +11,7 @@ export function setupProject() {
811
tmp.setup('./tmp')
912
.then(() => process.chdir('./tmp'))
1013
.then(() => ng(['new', 'foo', '--skip-install']))
14+
.then(() => addAppToProject())
1115
.then(done, done.fail);
1216
}, 10000);
1317

@@ -16,6 +20,17 @@ export function setupProject() {
1620
});
1721
}
1822

23+
function addAppToProject(): Promise<any> {
24+
const cliJson = path.join(path.join(process.cwd()), '.angular-cli.json');
25+
return readFile(cliJson, 'utf-8').then(content => {
26+
const json = JSON.parse(content);
27+
json.apps.push(({name: 'other', root: 'other/src', appRoot: ''}));
28+
return json;
29+
}).then(json => {
30+
return writeFile(cliJson, JSON.stringify(json, null, 2))
31+
});
32+
}
33+
1934
export {
2035
ng
2136
};

0 commit comments

Comments
 (0)