Skip to content
This repository was archived by the owner on Mar 26, 2018. It is now read-only.

Typescript support for generator-angular #313

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 121 additions & 7 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ var Generator = module.exports = function Generator(args, options) {
yeoman.generators.Base.apply(this, arguments);
this.argument('appname', { type: String, required: false });
this.appname = this.appname || path.basename(process.cwd());
this.indexFile = this.engine(this.read('../../templates/common/index.html'),
this);

args = ['main'];

Expand Down Expand Up @@ -42,16 +40,37 @@ var Generator = module.exports = function Generator(args, options) {
args.push('--minsafe');
}

// there's a problem with the hooks below running in this constructor,
// while useful data about what we want to generate is available only later,
// after we've asked the user. So we make an object here, push the user specified
// data in there, and make the object available by reference to the hooked subgenerators.
this.userChoices = {};

this.hookFor('angular:common', {
args: args
args: args,
options: {
options: {
userChoices: this.userChoices
}
}
});

this.hookFor('angular:main', {
args: args
args: args,
options: {
options: {
userChoices: this.userChoices
}
}
});

this.hookFor('angular:controller', {
args: args
args: args,
options: {
options: {
userChoices: this.userChoices
}
}
});

this.hookFor('karma', {
Expand All @@ -60,20 +79,99 @@ var Generator = module.exports = function Generator(args, options) {
options: {
coffee: this.options.coffee,
travis: true,
'skip-install': this.options['skip-install']
}
'skip-install': this.options['skip-install'],
typescript: this.options.typescript,
userChoices: this.userChoices
}
}
});

this.on('end', function () {
this.installDependencies({ skipInstall: this.options['skip-install'] });
});

// FIXME I'm pretty sure this is never used, so it shouldn't be here. It ends up reading
// the generator-angular's package.json instead of the one for the generated app anyway
this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(Generator, yeoman.generators.Base);

Generator.prototype._userMadeChoices = function _userMadeChoices(names) {
this._.extend(
this.userChoices,
this._.pick(this, names)
);
}

Generator.prototype.askForLanguage = function askForLanguage() {
var cb = this.async();

this.prompt([{
type: 'confirm',
name: 'coffee',
message: 'Would you like to use CoffeeScript?',
default: false
}, {
type: 'confirm',
name: 'typescript',
message: 'Would you like to use TypeScript?',
default: false
}], function (props) {
this.coffee = props.coffee;
this.typescript = props.typescript;
this.jquery = true; // default

if (this.typescript) {
this.jquery = true;
this.typescriptAppName = this._.camelize(this.appname) + "App";
this.typescriptAppType = this._.classify(this.appname) + "App";
}

this._userMadeChoices(['coffee', 'typescript', 'jquery', 'typescriptAppName', 'typescriptAppType']);

cb();
}.bind(this));
};

Generator.prototype.askForTypescriptFeatures = function askForTypescriptFeatures() {
if (!this.typescript) {
// default values, lest the variables are undefined inside the templates
this.typescriptConfig = false;
this.typescriptPartialsCache = false;
return;
}

var cb = this.async();

this.prompt([{
type: 'confirm',
name: 'typescriptConfig',
message: 'Would you like app configs? (convenient way to configure backend URLs, etc)',
default: true
}, {
type: 'confirm',
name: 'typescriptPartialsCache',
message: 'Would you like partials caching enabled? (bundles all .html partials in one file and seeds the ng cache)',
default: true
}], function (props) {
this.typescriptConfig = props.typescriptConfig;
this.typescriptPartialsCache = props.typescriptPartialsCache;

if (this.typescriptConfig) {
this.typescriptConfigName = this._.camelize(this.appname) + "Config";
}

if (this.typescriptPartialsCache) {
this.typescriptTemplatesModuleName = this._.camelize(this.appname) + "Templates";
}

this._userMadeChoices(['typescriptConfig', 'typescriptConfigName', 'typescriptPartialsCache', 'typescriptTemplatesModuleName']);

cb();
}.bind(this));
};

Generator.prototype.askForBootstrap = function askForBootstrap() {
var cb = this.async();

Expand All @@ -94,6 +192,10 @@ Generator.prototype.askForBootstrap = function askForBootstrap() {
this.bootstrap = props.bootstrap;
this.compassBootstrap = props.compassBootstrap;

if (this.bootstrap) {
this.jquery = true;
}

cb();
}.bind(this));
};
Expand Down Expand Up @@ -130,6 +232,16 @@ Generator.prototype.askForModules = function askForModules() {
}.bind(this));
};

/**
* This is a rather annoying order of execution dependency, but the index file needs
* to be initialized before we call appendFiles on it in some of the functions below,
* yet after all the user choices that may alter the index.html file have been made
*/
Generator.prototype.initializeIndexFile = function initializeIndexFile() {
this.indexFile = this.engine(this.read('../../templates/common/index.html'),
this);
}

// Waiting a more flexible solution for #138
Generator.prototype.bootstrapFiles = function bootstrapFiles() {
var sass = this.compassBootstrap;
Expand Down Expand Up @@ -206,6 +318,8 @@ Generator.prototype.extraModules = function extraModules() {
};

Generator.prototype.appJs = function appJs() {
if (this.typescript) return;

this.indexFile = this.appendFiles({
html: this.indexFile,
fileType: 'js',
Expand Down
5 changes: 3 additions & 2 deletions common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ var yeoman = require('yeoman-generator');

module.exports = Generator;

function Generator() {
function Generator(args, options) {
yeoman.generators.Base.apply(this, arguments);
this._.extend(this, options.userChoices);
}

util.inherits(Generator, yeoman.generators.Base);
Expand All @@ -17,5 +18,5 @@ Generator.prototype.setupEnv = function setupEnv() {
// directory into your users new application path
this.sourceRoot(path.join(__dirname, '../templates/common'));
this.directory('root', '.', true);
this.copy('gitignore', '.gitignore');
this.template('gitignore', '.gitignore');
};
21 changes: 18 additions & 3 deletions controller/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,34 @@ var ScriptBase = require('../script-base.js');

module.exports = Generator;

function Generator() {
function Generator(args, options) {
ScriptBase.apply(this, arguments);
this._.extend(this, options.userChoices);

// if the controller name is suffixed with ctrl, remove the suffix
// if the controller name is just "ctrl," don't append/remove "ctrl"
if (this.name && this.name.toLowerCase() !== 'ctrl' && this.name.substr(-4).toLowerCase() === 'ctrl') {
this.name = this.name.slice(0, -4);
}

if (this.typescript || this.options.typescript) {
var tsBaseName = this._.classify(this.name);
this.typescriptAppName = this.typescriptAppName || this.options.typescriptAppName;
this.tsAngularName = tsBaseName + "Ctrl";
this.tsClassName = tsBaseName + "Ctrl";
this.tsScopeInterfaceName = tsBaseName + "CtrlScope";
}
}

util.inherits(Generator, ScriptBase);

Generator.prototype.createControllerFiles = function createControllerFiles() {
this.appTemplate('controller');
this.testTemplate('spec/controller');
if (!(this.typescript || this.options.typescript)) {
this.appTemplate('controller');
this.testTemplate('spec/controller');
}
else {
this.appTemplate('controller', {addScriptToIndex: false});
this.testTemplate('spec/controller', {scriptSuffix: '.js'});
}
};
32 changes: 31 additions & 1 deletion main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,42 @@ var yeoman = require('yeoman-generator');

module.exports = Generator;

function Generator() {
function Generator(args, options) {
ScriptBase.apply(this, arguments);
this._.extend(this, options.userChoices);
}

util.inherits(Generator, ScriptBase);

Generator.prototype.createAppFile = function createAppFile() {
if (this.typescript) return;

this.appTemplate('app', 'scripts/app');
};

Generator.prototype.createTypescriptFiles = function createTypescriptFiles() {
if (!this.typescript) return;

var files = [
{ name: 'app.ts', dir: 'app' },
{ name: 'references.ts', dir: 'app' },
];

if (this.typescriptConfig) {
files = files.concat([
{ name: 'config.ts', dir: 'app' },
{ name: 'config.js', dir: 'resource' },
{ name: 'config_overrides.js', dir: 'resource' },
]);
}

if (this.typescriptPartialsCache) {
files.push(
{ name: 'templates.js', dir: 'resource' }
);
}

this._.each(files, function(file) {
this.template(file.name, path.join(this.env.options.appPath, file.dir, file.name));
}, this);
};
48 changes: 41 additions & 7 deletions script-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,40 @@ function Generator() {
this.env.options.testPath = this.env.options.testPath || 'test/spec';
}

var pkg = JSON.parse(this.readFileAsString(path.join(process.cwd(), 'package.json')));

if (typeof this.env.options.coffee === 'undefined') {
this.option('coffee');

// attempt to detect if user is using CS or not
// if cml arg provided, use that; else look for the existence of cs
if (!this.options.coffee &&
// TODO check pkg["yo-language"] === "coffee"
this.expandFiles(path.join(this.env.options.appPath, '/scripts/**/*.coffee'), {}).length > 0) {
this.options.coffee = true;
}

this.env.options.coffee = this.options.coffee;
}

if (typeof this.env.options.typescript === 'undefined') {
this.option('typescript');

// attempt to detect if user is using typescript or not
// if cml arg provided, use that; else look for yo-language in package.json
if (!this.options.typescript && pkg["yo-language"] === "typescript") {
this.options.typescript = true;
}

this.env.options.typescript = this.options.typescript;

if (this.options.typescript) {
if (pkg["yo-typescript-appName"]) {
this.env.options.typescriptAppName = this.options.typescriptAppName = pkg["yo-typescript-appName"];
}
}
}

if (typeof this.env.options.minsafe === 'undefined') {
this.option('minsafe');
this.env.options.minsafe = this.options.minsafe;
Expand All @@ -59,6 +80,12 @@ function Generator() {
sourceRoot += '-min';
}

// for now, no min-safe option for typescript, hence the ordering of these if blocks
if (this.env.options.typescript) {
sourceRoot = '/templates/typescript';
this.scriptSuffix = '.ts';
}

this.sourceRoot(path.join(__dirname, sourceRoot));

this.moduleName = this._.camelize(this.appname) + 'App';
Expand All @@ -84,18 +111,25 @@ Generator.prototype._dest = function (src) {
return path.join((this.namespace.join('/') || src), this.name);
};

Generator.prototype.appTemplate = function (src) {
Generator.prototype.appTemplate = function (src, options) {
options = options || {};
var scriptSuffix = options.scriptSuffix || this.scriptSuffix;

yeoman.generators.Base.prototype.template.apply(this, [
src + this.scriptSuffix,
path.join(this.env.options.appPath, this._dest(src)) + this.scriptSuffix
src + scriptSuffix,
path.join(this.env.options.appPath, this._dest(src)) + scriptSuffix
]);
this.addScriptToIndex(src);

if (options.addScriptToIndex !== false) this.addScriptToIndex(src);
};

Generator.prototype.testTemplate = function (src) {
Generator.prototype.testTemplate = function (src, options) {
options = options || {};
var scriptSuffix = options.scriptSuffix || this.scriptSuffix;

yeoman.generators.Base.prototype.template.apply(this, [
src + this.scriptSuffix,
path.join(this.env.options.testPath, this._dest(src)) + this.scriptSuffix
src + scriptSuffix,
path.join(this.env.options.testPath, this._dest(src)) + scriptSuffix
]);
};

Expand Down
Loading