UNPKG

8.23 kBPlain TextView Raw
1/// <reference path="typings/tsd.d.ts"/>
2
3import FinalModule = require('./FinalModule');
4import IGulp = require('./IGulp');
5import path = require('path');
6import fs = require('fs');
7import DependencyResolver = require('dependency-resolver');
8
9var wrap:(...args:any[])=>any = require('gulp-wrap');
10var concat:(...args:any[])=>any = require('gulp-concat');
11var tsc:(...args:any[])=>any = require('gulp-tsc');
12var uglify:(...args:any[])=>any = require('gulp-uglifyjs');
13var stylus:(...args:any[])=>any = require('gulp-stylus');
14var nib:(...args:any[])=>any = require('nib');
15var sourcemaps:any = require('gulp-sourcemaps');
16var runSequence:(...args:any[])=>any = require('run-sequence');
17var clean:any = require('gulp-clean');
18
19class FinalModules {
20
21 private modules:{[name:string]:FinalModule} = {};
22 private modulesInverted:DependencyResolver;
23 private sequence:(...args:any[])=>any
24
25 constructor(private modulesPath:string = 'public/src') {
26 this.modulesInverted = new DependencyResolver();
27 }
28
29 public add(name:string, dependencies:string[] = []):void {
30 this.modules[name] = new FinalModule(name, dependencies);
31 this.modulesInverted.add(name);
32 dependencies.forEach((dep:string):void => {
33 this.modulesInverted.setDependency(dep, name);
34 });
35 }
36
37 private map<T>(func:(mod:FinalModule)=>T):T[] {
38 return Object.keys(this.modules).map((key:string):T => func(this.modules[key]));
39 }
40
41 public generateTasks(gulp:IGulp.Gulp):void {
42 this.sequence = (<any>runSequence).use(gulp);
43
44 //Check for circular dependencies:
45 //sort() method will throw an error on circular dependencies
46 this.modulesInverted.sort();
47
48 this.map((mod:FinalModule):void => {
49 gulp.task('fm:' + mod.name + ':html', this.getHtmlTask(gulp, mod));
50 gulp.task('fm:' + mod.name + ':ts', mod.getDeps('fm:', ':ts'), this.getTsTask(gulp, mod));
51 gulp.task('fm:' + mod.name + ':ts:standalone', this.getTsTask(gulp, mod));
52 gulp.task('fm:' + mod.name + ':min', ['fm:' + mod.name + ':ts'], this.getMinTask(gulp, mod));
53 gulp.task('fm:' + mod.name + ':min:standalone', [mod.name + ':ts:standalone'], this.getMinTask(gulp, mod));
54 gulp.task('fm:' + mod.name + ':styl', this.getStylTask(gulp, mod));
55 gulp.task('fm:' + mod.name + ':clean', this.getCleanTask(gulp, mod));
56 gulp.task('fm:' + mod.name + ':watch:ts', this.getWatchTsTask(gulp, mod));
57 gulp.task('fm:' + mod.name + ':watch:styl', this.getWatchStylTask(gulp, mod));
58 gulp.task('fm:' + mod.name + ':watch:html', this.getWatchHtmlTask(gulp, mod));
59 gulp.task('fm:' + mod.name + ':watch', [mod.name + ':watch:ts', mod.name + ':watch:styl', mod.name + ':watch:html']);
60 });
61
62 gulp.task('fm:html', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':html'));
63 gulp.task('fm:ts', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':ts'));
64 gulp.task('fm:min', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':min'));
65 gulp.task('fm:styl', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':styl'));
66 gulp.task('fm:clean', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':clean'));
67 gulp.task('fm:watch:ts', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':watch:ts'));
68 gulp.task('fm:watch:styl', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':watch:styl'));
69 gulp.task('fm:watch:html', this.map((mod:FinalModule):string => 'fm:' + mod.name + ':watch:html'));
70 gulp.task('fm:watch', ['fm:watch:ts', 'fm:watch:styl', 'fm:watch:html']);
71 gulp.task('fm', ['fm:clean', 'fm:styl', 'fm:min', 'fm:html', 'fm:watch']);
72 }
73
74 private static varNameFilter(filePath:string):string {
75 return path.basename(filePath, '.html')
76 .replace(/[^a-zA-Z0-9\_\.]+/g, '-')
77 .replace(/-([a-z])/g, function (g) {
78 return g[1].toUpperCase();
79 })
80 .replace(/\-+/g, '');
81 }
82
83 private static escapeString(text:string):string {
84 return text
85 .replace(/\n/g, '')
86 .replace(/\'/g, '\\\'');
87 }
88
89
90
91 private getWatchTsTask(gulp:IGulp.Gulp, mod:FinalModule):()=>void {
92 return ():void => {
93 gulp.watch(this.modulesPath + '/' + mod.name + '/src/**/*.ts', ():void => {
94 var tasks:string[] = this.modulesInverted.resolve(mod.name)
95 .reverse()
96 .map((m:string):string => 'fm:' + m + ':min:standalone');
97 this.sequence.apply(this.sequence, tasks);
98 });
99 };
100 }
101
102 private getCleanTask(gulp:IGulp.Gulp, mod:FinalModule):()=>NodeJS.ReadWriteStream {
103 return ():NodeJS.ReadWriteStream => {
104 return gulp
105 .src(this.modulesPath + '/' + mod.name + '/build', {read: false})
106 .pipe(clean());
107 };
108 }
109
110 private getWatchStylTask(gulp:IGulp.Gulp, mod:FinalModule):()=>void {
111 return ():void => {
112 gulp.watch(this.modulesPath + '/' + mod.name + '/src/**/*.styl', ['fm:' + mod.name + ':styl']);
113 };
114 }
115
116 private getWatchHtmlTask(gulp:IGulp.Gulp, mod:FinalModule):()=>void {
117 return ():void => {
118 gulp.watch(this.modulesPath + '/' + mod.name + '/src/**/*.html', ['fm:' + mod.name + ':html']);
119 };
120 }
121
122 private getStylTask(gulp:IGulp.Gulp, mod:FinalModule):()=>NodeJS.ReadWriteStream {
123 return ():NodeJS.ReadWriteStream => {
124 return gulp.src([this.modulesPath + '/' + mod.name + '/src/**/*.styl'])
125 .pipe(stylus({
126 use: nib(),
127 sourcemap: {
128 inline: true,
129 sourceRoot: '',
130 basePath: 'css'
131 }
132 }))
133 .pipe(sourcemaps.init({
134 loadMaps: true
135 }))
136 .pipe(concat(mod.name + '.css'))
137 .pipe(sourcemaps.write('.', {
138 includeConent: false,
139 sourceRoot: ''
140 }))
141 .pipe(gulp.dest(this.modulesPath + '/' + mod.name + '/build/'));
142 };
143 }
144
145 private getMinTask(gulp:IGulp.Gulp, mod:FinalModule):()=>NodeJS.ReadWriteStream {
146 return ():NodeJS.ReadWriteStream => {
147
148 var inSourceMapPath:string = this.modulesPath + '/'
149 + mod.name + '/build/' + mod.name + '.js.map';
150
151 return gulp.src([this.modulesPath + '/' + mod.name + '/build/' + mod.name + '.js'])
152 .pipe(uglify(mod.name + '.min.js', {
153 outSourceMap: true,
154 output: {
155 source_map: {
156 file: mod.name + '.min.js',
157 root: '',
158 orig: fs.readFileSync(inSourceMapPath).toString()
159 }
160 }
161 }))
162 .pipe(gulp.dest(this.modulesPath + '/' + mod.name + '/build/'));
163 };
164 }
165
166 private getTsTask(gulp:IGulp.Gulp, mod:FinalModule):()=>NodeJS.ReadWriteStream {
167 return ():NodeJS.ReadWriteStream => {
168 var outDir = this.modulesPath + '/' + mod.name + '/build';
169
170 return gulp.src([
171 this.modulesPath + '/' + mod.name + '/src/**/*.ts',
172 '!' + this.modulesPath + '/' + mod.name + '/src/**/*.d.ts'
173 ])
174 .pipe(tsc({
175 emitError: false,
176 module: 'amd',
177 target: 'ES5',
178 outDir: outDir,
179 sourcemap: true,
180 sourceRoot: '',
181 declaration: true,
182 out: mod.name + '.js'
183 }))
184 .pipe(gulp.dest(outDir));
185 };
186 }
187
188 private getHtmlTask(gulp:IGulp.Gulp, mod:FinalModule):()=>NodeJS.ReadWriteStream {
189 return ():NodeJS.ReadWriteStream => {
190 var modNameSplit:string[] = mod.name.split('.');
191 var modVarInit:string;
192
193 var nameAlready:string = modNameSplit[0];
194 modVarInit = 'var $name = $name || {};'.replace(/\$name/g, nameAlready);
195
196 for (var i = 1; i < modNameSplit.length; i += 1) {
197 nameAlready += '.' + modNameSplit[i];
198 modVarInit += '\n$name = $name || {};'.replace(/\$name/g, nameAlready);
199 }
200
201 return gulp.src(this.modulesPath + '/' + mod.name + '/src/**/*.html')
202 .pipe(wrap('<%=mod.name%>.html.<%= varName(file.path) %> = \'<%=escape(contents)%>\';', {
203 mod: mod,
204 varName: FinalModules.varNameFilter,
205 escape: FinalModules.escapeString
206 }))
207 .pipe(concat(mod.name + '.html.js'))
208 .pipe(wrap(
209 modVarInit + '\n<%=mod.name%>.html = {};\n\n<%=contents%>',
210 {mod: mod}
211 ))
212 .pipe(gulp.dest(this.modulesPath + '/' + mod.name + '/build'));
213 };
214 }
215}
216
217export = FinalModules;