diff --git a/README.md b/README.md index e1db87493856..f16284610773 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,14 @@ You can use the `ng generate` (or just `ng g`) command to generate Angular compo ```bash ng generate component my-new-component ng g component my-new-component # using the alias + +# components support relative path generation +# if in the directory src/app/feature/ and you run +ng g component new-cmp +# your component will be generated in src/app/feature/new-cmp +# but if you were to run +ng g component ../newer-cmp +# your component will be generated in src/app/newer-cmp ``` You can find all possible blueprints in the table below: diff --git a/addon/ng2/blueprints/component-test/index.js b/addon/ng2/blueprints/component-test/index.js index 384ca8910e60..557bbba0b12f 100644 --- a/addon/ng2/blueprints/component-test/index.js +++ b/addon/ng2/blueprints/component-test/index.js @@ -1,3 +1,12 @@ -var component = require('../component'); - -module.exports = component; +module.exports = { + description: '', + + // ****************************************************** + // ****************************************************** + // LEAVE THIS HERE + // Must override install to prevent ember's component tests + // ****************************************************** + // ****************************************************** + + install: function(options){} +}; diff --git a/addon/ng2/blueprints/component-test/files/src/app/__path__/__name__/__name__.spec.ts b/addon/ng2/blueprints/component/files/src/app/__path__/__name__/__name__.spec.ts similarity index 100% rename from addon/ng2/blueprints/component-test/files/src/app/__path__/__name__/__name__.spec.ts rename to addon/ng2/blueprints/component/files/src/app/__path__/__name__/__name__.spec.ts diff --git a/addon/ng2/blueprints/component/files/src/app/__path__/__name__/__name__.ts b/addon/ng2/blueprints/component/files/src/app/__path__/__name__/__name__.ts index bea0720ce449..73a879eb92fb 100644 --- a/addon/ng2/blueprints/component/files/src/app/__path__/__name__/__name__.ts +++ b/addon/ng2/blueprints/component/files/src/app/__path__/__name__/__name__.ts @@ -3,8 +3,8 @@ import {Component} from 'angular2/core'; @Component({ selector: '<%= dasherizedModuleName %>', - templateUrl: 'app/components/<%= dasherizedModuleName %>/<%= dasherizedModuleName %>.html', - styleUrls: ['app/components/<%= dasherizedModuleName %>/<%= dasherizedModuleName %>.css'], + templateUrl: 'app/<%= dynamicPath %>/<%= dasherizedModuleName %>/<%= dasherizedModuleName %>.html', + styleUrls: ['app/<%= dynamicPath %>/<%= dasherizedModuleName %>/<%= dasherizedModuleName %>.css'], providers: [], directives: [], pipes: [] diff --git a/addon/ng2/blueprints/component/index.js b/addon/ng2/blueprints/component/index.js index 1d6122b5986d..69d536712eda 100644 --- a/addon/ng2/blueprints/component/index.js +++ b/addon/ng2/blueprints/component/index.js @@ -1,26 +1,59 @@ var stringUtils = require('ember-cli/lib/utilities/string'); var path = require('path'); +var process = require('process'); module.exports = { description: '', - - locals: function(options) { - var parsedPath = path.parse(options.entity.name); - // build the locals for generating the name & path - return { + + normalizeEntityName: function(entityName){ + var cwd = this.project.cli.testing + ? process.cwd() + : process.env.PWD; + + var rootPath = path.join(this.project.root, 'src', 'app'); + + var outputPath = path.join(rootPath, entityName); + + if (entityName.indexOf(path.sep) === 0) { + outputPath = path.join(rootPath, entityName.substr(1)); + } else if (cwd.indexOf(rootPath) >= 0) { + outputPath = path.join(cwd, entityName); + } else if (cwd.indexOf(path.join(this.project.root, 'src')) >= 0 + && entityName.indexOf('app') === 0) { + outputPath = path.join(cwd, entityName); + } else if (cwd.indexOf(path.join(this.project.root, 'src')) >= 0) { + outputPath = path.join(cwd, 'app', entityName); + } + + if (outputPath.indexOf(rootPath) < 0) { + throw `Invalid component path: "${entityName}" cannot be ` + + `above the "${path.join('src', 'app')}" directory`; + } + + var adjustedPath = outputPath.replace(rootPath, ''); + + var parsedPath = path.parse(adjustedPath); + this.dynamicPath = { name: parsedPath.name, path: parsedPath.dir }; + return parsedPath.name; + }, + + locals: function(options){ + return { + dynamicPath: this.dynamicPath.path + } }, fileMapTokens: function(options) { // Return custom template variables here. return { - __name__: function(options) { - return options.locals.name; + __name__: (options) => { + return this.dynamicPath.name; }, - __path__: function(options) { - return options.locals.path || 'components'; + __path__: (options) => { + return this.dynamicPath.path; } }; } diff --git a/addon/ng2/blueprints/service/files/src/app/__path__/__name__/__name__.spec.ts b/addon/ng2/blueprints/service/files/src/app/__path__/__name__/__name__.spec.ts new file mode 100644 index 000000000000..5650fee31b81 --- /dev/null +++ b/addon/ng2/blueprints/service/files/src/app/__path__/__name__/__name__.spec.ts @@ -0,0 +1,25 @@ +import { + it, + iit, + describe, + ddescribe, + expect, + inject, + injectAsync, + TestComponentBuilder, + beforeEachProviders +} from 'angular2/testing'; +import {provide} from 'angular2/core'; +import {<%= classifiedModuleName %>} from './<%= dasherizedModuleName %>'; + + +describe('<%= classifiedModuleName %> Service', () => { + + beforeEachProviders(() => [<%= classifiedModuleName %>]); + + + it('should ...', inject([<%= classifiedModuleName %>], (service:<%= classifiedModuleName %>) => { + + })); + +}); diff --git a/addon/ng2/blueprints/service/files/src/app/__path__/__name__/__name__.ts b/addon/ng2/blueprints/service/files/src/app/__path__/__name__/__name__.ts new file mode 100644 index 000000000000..b6affa0cde77 --- /dev/null +++ b/addon/ng2/blueprints/service/files/src/app/__path__/__name__/__name__.ts @@ -0,0 +1,9 @@ +import {Injectable} from 'angular2/core'; + + +@Injectable() +export class <%= classifiedModuleName %> { + + constructor() {} + +} diff --git a/tests/acceptance/generate-component.spec.js b/tests/acceptance/generate-component.spec.js new file mode 100644 index 000000000000..aa287b6ab5e7 --- /dev/null +++ b/tests/acceptance/generate-component.spec.js @@ -0,0 +1,180 @@ +'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/collection/forEach'); +var walkSync = require('walk-sync'); +var Blueprint = require('ember-cli/lib/models/blueprint'); +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 EOL = require('os').EOL; +var path = require('path'); +var Promise = require('ember-cli/lib/ext/promise'); + +describe('Acceptance: ng generate component', 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 component my-comp', function() { + return ng([ + 'generate', + 'component', + 'my-comp' + ]) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }); + }); + + it('ng generate component test' + path.sep + 'my-comp', function() { + return ng([ + 'generate', + 'component', + 'test' + path.sep + 'my-comp' + ]) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'test', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }); + }); + + it('ng generate component test' + path.sep + '..' + path.sep + 'my-comp', function() { + return ng([ + 'generate', + 'component', + 'test' + path.sep + '..' + path.sep + 'my-comp' + ]) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }); + }); + + it('ng generate component my-comp from a child dir', () => { + return new Promise(function (resolve, reject) { + process.chdir('./src'); + resolve(); + }) + .then(_ => process.chdir('./app')) + .then(_ => fs.mkdirsSync('./1')) + .then(_ => process.chdir('./1')) + .then(_ => { + process.env.CWD = process.cwd(); + return ng([ + 'generate', + 'component', + 'my-comp' + ]) + }) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }, err => console.log('ERR: ', err)); + }); + + it('ng generate component child-dir' + path.sep + 'my-comp from a child dir', () => { + return new Promise(function (resolve, reject) { + process.chdir('./src'); + resolve(); + }) + .then(_ => process.chdir('./app')) + .then(_ => fs.mkdirsSync('./1')) + .then(_ => process.chdir('./1')) + .then(_ => { + process.env.CWD = process.cwd(); + return ng([ + 'generate', + 'component', + 'child-dir' + path.sep + 'my-comp' + ]) + }) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'child-dir', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }, err => console.log('ERR: ', err)); + }); + + it('ng generate component child-dir' + path.sep + '..' + path.sep + 'my-comp from a child dir', () => { + return new Promise(function (resolve, reject) { + process.chdir('./src'); + resolve(); + }) + .then(_ => process.chdir('./app')) + .then(_ => fs.mkdirsSync('./1')) + .then(_ => process.chdir('./1')) + .then(_ => { + process.env.CWD = process.cwd(); + return ng([ + 'generate', + 'component', + 'child-dir' + path.sep + '..' + path.sep + 'my-comp' + ]) + }) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '1', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }, err => console.log('ERR: ', err)); + }); + + it('ng generate component ' + path.sep + 'my-comp from a child dir, gens under ' + path.join('src', 'app'), () => { + return new Promise(function (resolve, reject) { + process.chdir('./src'); + resolve(); + }) + .then(_ => process.chdir('./app')) + .then(_ => fs.mkdirsSync('./1')) + .then(_ => process.chdir('./1')) + .then(_ => { + process.env.CWD = process.cwd(); + return ng([ + 'generate', + 'component', + path.sep + 'my-comp' + ]) + }) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(true); + }, err => console.log('ERR: ', err)); + }); + + it('ng generate component ..' + path.sep + 'my-comp from root dir will fail', () => { + return ng([ + 'generate', + 'component', + '..' + path.sep + 'my-comp' + ]) + .then(_ => { + var testPath = path.join(root, 'tmp', 'foo', 'src', 'app', '..', 'my-comp', 'my-comp.ts'); + expect(existsSync(testPath)).to.equal(false); + }); + }); +}); \ No newline at end of file