Skip to content

Commit

Permalink
feat(blueprints): adding generation of routing config
Browse files Browse the repository at this point in the history
  • Loading branch information
zackarychapple committed Mar 24, 2016
1 parent 6830cef commit e32fd1c
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 18 deletions.
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,21 +118,37 @@ with two sub-routes. The file structure will be as follows:
| | |-- hero.service.ts
| |-- ...
|-- app.ts
|-- route-config.ts
...
```

Afterwards to use the new route open your main app component, import
`hero-root.component.ts` and add it in the route config:
By default the cli will add the import statements for HeroList and HeroDetail to
`hero-root.component.ts`:

```
@RouteConfig([
{path:'/hero/...', name: 'HeroRoot', component: HeroRoot}
{path:'/', name: 'HeroList', component: HeroListComponent, useAsDefault: true},
{path:'/:id', name: 'HeroDetail', component: HeroDetailComponent}
])
```

The generated `route-config.ts` file is also updated with the following:

```
// DO NOT EDIT THIS FILE
// IT IS AUTO GENERATED BY ANGULAR-CLI
import {HeroRoot} from './hero/hero-root.component';
export const CliRouteConfig = [
{path:'/hero/...', name: 'HeroRoot', component: HeroRoot}
];
```

Visiting `http://localhost:4200/hero` will show the hero list.


There is an optional flag for `skip-router-generation` which will not add the route to the `CliRouteConfig` for the application.

### Creating a build

```bash
Expand Down
3 changes: 3 additions & 0 deletions addon/ng2/blueprints/ng2/files/angular-cli.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"routes": []
}
5 changes: 3 additions & 2 deletions addon/ng2/blueprints/ng2/files/src/app/__name__.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router';

import {CliRouteConfig} from './route-config';

@Component({
selector: '<%= htmlComponentName %>-app',
Expand All @@ -11,7 +11,8 @@ import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router'
})
@RouteConfig([

])
].concat(CliRouteConfig))

export class <%= jsComponentName %>App {
defaultMeaning: number = 42;

Expand Down
7 changes: 7 additions & 0 deletions addon/ng2/blueprints/ng2/files/src/app/route-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

// DO NOT EDIT THIS FILE
// IT IS AUTO GENERATED BY ANGULAR-CLI

export const CliRouteConfig = [

];
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// DO NOT EDIT THIS FILE
// IT IS AUTO GENERATED BY ANGULAR-CLI
<%= imports %>

export const CliRouteConfig = [
<%= routeDefinitions %>
];
39 changes: 39 additions & 0 deletions addon/ng2/blueprints/route-config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
var fs = require('fs-extra');
var path = require('path');

var imports, routeDefinitions;

module.exports = {
description: 'Registers the route with the router.',

locals: function (options) {
return generateLocals.call(this, options);
},

beforeInstall: function (options) {
var routeConfigPath = path.join(options.project.root, 'src', 'app', 'route-config.ts');
try {
fs.unlinkSync(routeConfigPath);
} catch (e) {
}
}
};

function generateLocals(options) {
var ngCliConfigPath = path.join(options.project.root, 'angular-cli.json');
var ngCliConfig = JSON.parse(fs.readFileSync(ngCliConfigPath, 'utf-8'));

imports = ngCliConfig.routes.map(route =>
`import {${route.component}} from '${route.componentPath}';`)
.join('\n');

routeDefinitions = ngCliConfig.routes.map(route =>
`{path: '${route.routePath}', name: '${route.component}', component: ${route.component}},`
)
.join('\n');

return {
imports,
routeDefinitions
}
}
81 changes: 68 additions & 13 deletions addon/ng2/blueprints/route/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,71 @@
var stringUtils = require('ember-cli/lib/utilities/string');
var fs = require('fs-extra');
var path = require('path');
var chalk = require('chalk');

module.exports = {
description: ''

//locals: function(options) {
// // Return custom template variables here.
// return {
//
// };
//}

// afterInstall: function(options) {
// // Perform extra work here.
// }
description: 'Generates a route and a template.',

availableOptions: [{
name: 'skip-router-generation',
type: Boolean,
default: false,
aliases: ['srg']
}, {
name: 'default',
type: Boolean,
default: false
}],

beforeInstall: function (options, locals) {
if (!options.skipRouterGeneration) {
updateRouteConfig.call(this, 'add', options, locals);
}
},

afterInstall: function (options, locals) {
if (!options.skipRouterGeneration) {
return this.lookupBlueprint('route-config')
.install(options);
}
},

beforeUninstall: function (options, locals) {
updateRouteConfig.call(this, 'remove', options, locals);
},

afterUninstall: function (options, locals) {
return this.lookupBlueprint('route-config')
.install(options);
}
};

function updateRouteConfig(action, options, locals) {
var entity = options.entity;
var actionColorMap = {
add: 'green',
remove: 'red'
};
var color = actionColorMap[action] || 'gray';

this._writeStatusToUI(chalk[color], action + ' route', entity.name);

var ngCliConfigPath = path.join(options.project.root, 'angular-cli.json');

// TODO use default option
var route = {
routePath: `/${locals.dasherizedModuleName}/...`,
component: `${locals.classifiedModuleName}Root`,
componentPath: `./${locals.dasherizedModuleName}/${locals.dasherizedModuleName}-root.component`
};

var ngCliConfig = JSON.parse(fs.readFileSync(ngCliConfigPath, 'utf-8'));
if (action === 'add' && ngCliConfig.routes.findIndex(el => el.routePath === route.routePath) === -1) {
ngCliConfig.routes.push(route)
} else if (action === 'remove') {
var idx = ngCliConfig.routes.findIndex(el => el.routePath === route.routePath);
if (idx > -1) {
ngCliConfig.routes.splice(idx, 1);
}
}
fs.writeFileSync(ngCliConfigPath, JSON.stringify(ngCliConfig, null, 2));
}
124 changes: 124 additions & 0 deletions tests/acceptance/generate-route.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
'use strict';

var fs = require('fs-extra');
var ng = require('../helpers/ng');
var existsSync = require('exists-sync');
var expect = require('chai').expect;
var forEach = require('lodash/forEach');
var path = require('path');
var tmp = require('../helpers/tmp');
var root = process.cwd();
var util = require('util');
var conf = require('ember-cli/tests/helpers/conf');
var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-route');
var appPath = path.join(root, 'tmp', 'foo', 'src', 'app');
var routeRegex = /name: 'MyRouteRoot'/g;
var route = {
routePath: `/my-route/...`,
component: `MyRouteRoot`,
componentPath: `./my-route/my-route-root.component`
};

var fileExpectations = function (expectation) {
expect(existsSync(path.join(testPath, 'my-route.service.spec.ts'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route.service.ts'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-list.component.ts'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-list.component.spec.ts'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-list.component.html'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-list.component.css'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-detail.component.ts'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-detail.component.spec.ts'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-detail.component.html'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-detail.component.css'))).to.equal(expectation);
expect(existsSync(path.join(testPath, 'my-route-root.component.ts'))).to.equal(expectation);
};

describe('Acceptance: ng generate route', function () {
before(conf.setup);

after(conf.restore);

beforeEach(function () {
return tmp.setup('./tmp')
.then(function () {
process.chdir('./tmp');
})
.then(function () {
return ng([
'new',
'foo',
'--skip-npm',
'--skip-bower'
]);
});
});

afterEach(function () {
this.timeout(10000);

return tmp.teardown('./tmp');
});

it('ng generate route my-route', function () {
return ng([
'generate',
'route',
'my-route'
])
.then(_ => {
var ngCliConfig = JSON.parse(fs.readFileSync(path.join(root, 'tmp', 'foo', 'angular-cli.json'), 'utf-8'));
var routeConfigString = fs.readFileSync(path.join(appPath, 'route-config.ts'), 'utf-8').toString();
expect(routeConfigString.match(routeRegex).length).to.equal(1);

fileExpectations(true);

expect(ngCliConfig.routes[0]).to.deep.equal(route);
});
});
it('ng generate route my-route with skip-router-generation flag does not generate router config', function () {
return ng([
'generate',
'route',
'my-route',
'--skip-router-generation'
])
.then(_ => {
var ngCliConfig = JSON.parse(fs.readFileSync(path.join(root, 'tmp', 'foo', 'angular-cli.json'), 'utf-8'));

fileExpectations(true);

expect(ngCliConfig.routes.length).to.equal(0);
});
});
it('ng generate route my-route then destroy', function () {
return ng([
'generate',
'route',
'my-route'
])
.then(() => {
var ngCliConfig = JSON.parse(fs.readFileSync(path.join(root, 'tmp', 'foo', 'angular-cli.json'), 'utf-8'));
var routeConfigString = fs.readFileSync(path.join(appPath, 'route-config.ts'), 'utf-8').toString();
expect(routeConfigString.match(routeRegex).length).to.equal(1);

fileExpectations(true);

expect(ngCliConfig.routes.length).to.equal(1);
expect(ngCliConfig.routes[0]).to.deep.equal(route);
}).then(() => {
return ng([
'destroy',
'route',
'my-route'
]).then(() => {
var ngCliConfig = JSON.parse(fs.readFileSync(path.join(root, 'tmp', 'foo', 'angular-cli.json'), 'utf-8'));
var routeConfigString = fs.readFileSync(path.join(appPath, 'route-config.ts'), 'utf-8').toString();
expect(routeConfigString.match(routeRegex)).to.equal(null);

fileExpectations(false);

expect(ngCliConfig.routes.length).to.equal(0);
})
});
});
});

0 comments on commit e32fd1c

Please sign in to comment.