Skip to content

Commit 4de2e96

Browse files
Basically working Yeoman template generator generator
1 parent fc705e8 commit 4de2e96

12 files changed

Lines changed: 281 additions & 52 deletions

File tree

templates/yeoman/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "index.js",
66
"scripts": {
77
"test": "echo \"Error: no test specified\" && exit 1",
8-
"build": "tsc && node ./built/CreateGenerator.js"
8+
"build": "tsc && node ./tmp/build/build.js"
99
},
1010
"author": "Microsoft",
1111
"license": "Apache-2.0",

templates/yeoman/src/CreateGenerator.ts

Lines changed: 0 additions & 48 deletions
This file was deleted.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import * as glob from 'glob';
2+
import * as gitignore from 'gitignore-parser';
3+
import * as fs from 'fs';
4+
import * as path from 'path';
5+
import * as _ from 'lodash';
6+
import * as mkdirp from 'mkdirp';
7+
import * as rimraf from 'rimraf';
8+
9+
const textFileExtensions = ['.gitignore', '.config', '.cs', '.cshtml', 'Dockerfile', '.html', '.js', '.json', '.jsx', '.md', '.ts', '.tsx', '.xproj'];
10+
11+
const templates = {
12+
'angular-2': '../../templates/Angular2Spa/',
13+
'knockout': '../../templates/KnockoutSpa/',
14+
'react-redux': '../../templates/ReactReduxSpa/',
15+
'react': '../../templates/ReactSpa/'
16+
};
17+
18+
const contentReplacements: { from: RegExp, to: string }[] = [
19+
{ from: /\bWebApplicationBasic\b/g, to: '<%= namePascalCase %>' },
20+
{ from: /<ProjectGuid>[0-9a-f\-]{36}<\/ProjectGuid>/g, to: '<ProjectGuid><%= projectGuid %></ProjectGuid>' },
21+
{ from: /<RootNamespace>.*?<\/RootNamespace>/g, to: '<RootNamespace><%= namePascalCase %></RootNamespace>'},
22+
{ from: /\s*<BaseIntermediateOutputPath.*?<\/BaseIntermediateOutputPath>/g, to: '' },
23+
{ from: /\s*<OutputPath.*?<\/OutputPath>/g, to: '' },
24+
];
25+
26+
const filenameReplacements: { from: RegExp, to: string }[] = [
27+
{ from: /.*\.xproj$/, to: 'tokenreplace-namePascalCase.xproj' }
28+
];
29+
30+
function isTextFile(filename: string): boolean {
31+
return textFileExtensions.indexOf(path.extname(filename).toLowerCase()) >= 0;
32+
}
33+
34+
function writeFileEnsuringDirExists(root: string, filename: string, contents: string | Buffer) {
35+
let fullPath = path.join(root, filename);
36+
mkdirp.sync(path.dirname(fullPath));
37+
fs.writeFileSync(fullPath, contents);
38+
}
39+
40+
function listFilesExcludingGitignored(root: string): string[] {
41+
let gitIgnorePath = path.join(root, '.gitignore');
42+
let gitignoreEvaluator = fs.existsSync(gitIgnorePath)
43+
? gitignore.compile(fs.readFileSync(gitIgnorePath, 'utf8'))
44+
: { accepts: () => true };
45+
return glob.sync('**/*', { cwd: root, dot: true, nodir: true })
46+
.filter(fn => gitignoreEvaluator.accepts(fn));
47+
}
48+
49+
function writeTemplate(sourceRoot: string, destRoot: string) {
50+
listFilesExcludingGitignored(sourceRoot).forEach(fn => {
51+
let sourceContent = fs.readFileSync(path.join(sourceRoot, fn));
52+
53+
// For text files, replace hardcoded values with template tags
54+
if (isTextFile(fn)) {
55+
let sourceText = sourceContent.toString('utf8');
56+
contentReplacements.forEach(replacement => {
57+
sourceText = sourceText.replace(replacement.from, replacement.to);
58+
});
59+
60+
sourceContent = new Buffer(sourceText, 'utf8');
61+
}
62+
63+
// Also apply replacements in filenames
64+
filenameReplacements.forEach(replacement => {
65+
fn = fn.replace(replacement.from, replacement.to);
66+
});
67+
68+
writeFileEnsuringDirExists(destRoot, fn, sourceContent);
69+
});
70+
}
71+
72+
function copyRecursive(sourceRoot: string, destRoot: string, matchGlob: string) {
73+
glob.sync(matchGlob, { cwd: sourceRoot, dot: true, nodir: true })
74+
.forEach(fn => {
75+
const sourceContent = fs.readFileSync(path.join(sourceRoot, fn));
76+
writeFileEnsuringDirExists(destRoot, fn, sourceContent);
77+
});
78+
}
79+
80+
const outputRoot = './generator-aspnet-spa';
81+
const outputTemplatesRoot = path.join(outputRoot, 'app/templates');
82+
rimraf.sync(outputTemplatesRoot);
83+
84+
// Copy template files
85+
_.forEach(templates, (templateRootDir, templateName) => {
86+
const outputDir = path.join(outputTemplatesRoot, templateName);
87+
writeTemplate(templateRootDir, outputDir);
88+
});
89+
90+
// Also copy the generator files (that's the compiled .js files, plus all other non-.ts files)
91+
const tempRoot = './tmp';
92+
copyRecursive(path.join(tempRoot, 'generator'), outputRoot, '**/*.js');
93+
copyRecursive('./src/generator', outputRoot, '**/!(*.ts)');
94+
95+
// Clean up
96+
rimraf.sync(tempRoot);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as path from 'path';
2+
import * as yeoman from 'yeoman-generator';
3+
import * as uuid from 'node-uuid';
4+
import * as glob from 'glob';
5+
const toPascalCase = require('to-pascal-case');
6+
7+
const templates = [
8+
{ value: 'angular-2', name: 'Angular 2' },
9+
{ value: 'knockout', name: 'Knockout' },
10+
{ value: 'react', name: 'React' },
11+
{ value: 'react-redux', name: 'React with Redux' }
12+
];
13+
14+
class MyGenerator extends yeoman.Base {
15+
private _answers: any;
16+
17+
constructor(args: string | string[], options: any) {
18+
super(args, options);
19+
}
20+
21+
prompting() {
22+
const done = this.async();
23+
24+
this.prompt([{
25+
type: 'list',
26+
name: 'framework',
27+
message: 'Framework',
28+
choices: templates
29+
}, {
30+
type: 'input',
31+
name: 'name',
32+
message: 'Your project name',
33+
default: this.appname
34+
}], answers => {
35+
this._answers = answers;
36+
this._answers.namePascalCase = toPascalCase(answers.name);
37+
this._answers.projectGuid = uuid.v4();
38+
done();
39+
})
40+
}
41+
42+
writing() {
43+
var templateRoot = this.templatePath(this._answers.framework);
44+
glob.sync('**/*', { cwd: templateRoot, dot: true, nodir: true }).forEach(fn => {
45+
// Token replacement in filenames
46+
let outputFn = fn.replace(/tokenreplace\-([^\.\/]*)/g, (substr, token) => this._answers[token]);
47+
48+
this.fs.copyTpl(
49+
path.join(templateRoot, fn),
50+
this.destinationPath(outputFn),
51+
this._answers
52+
);
53+
});
54+
}
55+
}
56+
57+
declare var module: any;
58+
(module).exports = MyGenerator;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "generator-aspnet-spa",
3+
"version": "0.1.0",
4+
"description": "Single-Page App templates for ASP.NET Core",
5+
"files": ["templates"],
6+
"keywords": ["yeoman-generator"],
7+
"dependencies": {
8+
"yeoman-generator": "^0.20.2"
9+
}
10+
}

templates/yeoman/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
"moduleResolution": "node",
44
"target": "es5",
5-
"outDir": "built",
5+
"outDir": "tmp",
66
"sourceMap": false
77
},
88
"exclude": [

templates/yeoman/tsd.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"commit": "544a35a10866b32afda9c7f029c0764558563f4f"
1010
},
1111
"node/node.d.ts": {
12-
"commit": "544a35a10866b32afda9c7f029c0764558563f4f"
12+
"commit": "08ed4e9f1869e37e29514d862e0158b40e550232"
1313
},
1414
"glob/glob.d.ts": {
1515
"commit": "544a35a10866b32afda9c7f029c0764558563f4f"
@@ -25,6 +25,15 @@
2525
},
2626
"rimraf/rimraf.d.ts": {
2727
"commit": "544a35a10866b32afda9c7f029c0764558563f4f"
28+
},
29+
"node-uuid/node-uuid.d.ts": {
30+
"commit": "08ed4e9f1869e37e29514d862e0158b40e550232"
31+
},
32+
"node-uuid/node-uuid-base.d.ts": {
33+
"commit": "08ed4e9f1869e37e29514d862e0158b40e550232"
34+
},
35+
"node-uuid/node-uuid-cjs.d.ts": {
36+
"commit": "08ed4e9f1869e37e29514d862e0158b40e550232"
2837
}
2938
}
3039
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Type definitions for node-uuid.js
2+
// Project: https://github.com/broofa/node-uuid
3+
// Definitions by: Jeff May <https://github.com/jeffmay>
4+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5+
6+
/** Common definitions for all environments */
7+
declare namespace __NodeUUID {
8+
interface UUIDOptions {
9+
10+
/**
11+
* Node id as Array of 6 bytes (per 4.1.6).
12+
* Default: Randomly generated ID. See note 1.
13+
*/
14+
node?: any[];
15+
16+
/**
17+
* (Number between 0 - 0x3fff) RFC clock sequence.
18+
* Default: An internally maintained clockseq is used.
19+
*/
20+
clockseq?: number;
21+
22+
/**
23+
* (Number | Date) Time in milliseconds since unix Epoch.
24+
* Default: The current time is used.
25+
*/
26+
msecs?: number|Date;
27+
28+
/**
29+
* (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if msecs is unspecified.
30+
* Default: internal uuid counter is used, as per 4.2.1.2.
31+
*/
32+
nsecs?: number;
33+
}
34+
35+
interface UUID {
36+
v1(options?: UUIDOptions): string;
37+
v1(options?: UUIDOptions, buffer?: number[], offset?: number): number[];
38+
39+
v4(options?: UUIDOptions): string;
40+
v4(options?: UUIDOptions, buffer?: number[], offset?: number): number[];
41+
42+
parse(id: string, buffer?: number[], offset?: number): number[];
43+
44+
unparse(buffer: number[], offset?: number): string;
45+
}
46+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Type definitions for node-uuid.js
2+
// Project: https://github.com/broofa/node-uuid
3+
// Definitions by: Jeff May <https://github.com/jeffmay>
4+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5+
6+
/// <reference path="./node-uuid-base.d.ts" />
7+
8+
/**
9+
* Expose as CommonJS module
10+
* For use in node environment or browser environment (using webpack or other module loaders)
11+
*/
12+
declare module "node-uuid" {
13+
var uuid: __NodeUUID.UUID;
14+
export = uuid;
15+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Type definitions for node-uuid.js
2+
// Project: https://github.com/broofa/node-uuid
3+
// Definitions by: Jeff May <https://github.com/jeffmay>
4+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5+
6+
/// <reference path="../node/node.d.ts" />
7+
/// <reference path="./node-uuid-base.d.ts" />
8+
/// <reference path="./node-uuid-cjs.d.ts" />
9+
10+
/**
11+
* Definitions for use in node environment
12+
*
13+
* !! For browser enviroments, use node-uuid-global or node-uuid-cjs
14+
*/
15+
declare module __NodeUUID {
16+
/**
17+
* Overloads for node environment
18+
* We need to duplicate some declarations because
19+
* interface merging doesn't work with overloads
20+
*/
21+
interface UUID {
22+
v1(options?: UUIDOptions): string;
23+
v1(options?: UUIDOptions, buffer?: number[], offset?: number): number[];
24+
v1(options?: UUIDOptions, buffer?: Buffer, offset?: number): Buffer;
25+
26+
v4(options?: UUIDOptions): string;
27+
v4(options?: UUIDOptions, buffer?: number[], offset?: number): number[];
28+
v4(options?: UUIDOptions, buffer?: Buffer, offset?: number): Buffer;
29+
30+
parse(id: string, buffer?: number[], offset?: number): number[];
31+
parse(id: string, buffer?: Buffer, offset?: number): Buffer;
32+
33+
unparse(buffer: number[], offset?: number): string;
34+
unparse(buffer: Buffer, offset?: number): string;
35+
}
36+
}

0 commit comments

Comments
 (0)