turbo-gulp
Version:
Gulp tasks to boost high-quality projects.
127 lines (112 loc) • 4.72 kB
text/typescript
import { FSWatcher } from "fs";
import { Gulp } from "gulp";
import gulpRename from "gulp-rename";
import gulpSourceMaps from "gulp-sourcemaps";
import gulpTypescript from "gulp-typescript";
import { Incident } from "incident";
import merge from "merge2";
import { posix as posixPath } from "path";
import { CompilerOptionsJson } from "../options/tsc";
import { OutModules } from "../options/typescript";
import { TaskFunction } from "../utils/gulp-task-function";
import { deleteUndefinedProperties } from "../utils/utils";
import { ResolvedTsLocations, resolveTsLocations, TypescriptConfig } from "./_typescript";
type TypescriptErrorHash = string;
function hashTypescriptError(error: gulpTypescript.reporter.TypeScriptError): TypescriptErrorHash {
return JSON.stringify({
fileName: error.fullFilename,
code: error.diagnostic.code,
startPosition: error.startPosition,
endPosition: error.endPosition,
});
}
class TypescriptReporter implements gulpTypescript.reporter.Reporter {
readonly throwOnError: boolean;
private readonly baseReporter: gulpTypescript.reporter.Reporter;
private readonly reported: Set<TypescriptErrorHash>;
constructor(throwOnError: boolean) {
this.baseReporter = gulpTypescript.reporter.defaultReporter();
this.reported = new Set();
this.throwOnError = throwOnError;
}
error(error: gulpTypescript.reporter.TypeScriptError, typescript: any): void {
const hash: TypescriptErrorHash = hashTypescriptError(error);
if (this.reported.has(hash)) {
return;
}
this.reported.add(hash);
this.baseReporter.error!(error, typescript);
}
finish(compilerResult: gulpTypescript.reporter.CompilationResult): void {
this.baseReporter.finish!(compilerResult);
if (this.throwOnError && this.reported.size > 0) {
throw Incident("TypescriptError");
}
}
}
export function getBuildTypescriptTask(
gulp: Gulp,
options: TypescriptConfig,
throwOnError: boolean = true,
): TaskFunction {
const resolved: ResolvedTsLocations = resolveTsLocations(options);
const tscOptions: CompilerOptionsJson = {
...options.tscOptions,
rootDir: resolved.rootDir,
outDir: resolved.outDir,
typeRoots: resolved.typeRoots,
};
deleteUndefinedProperties(tscOptions);
const task: TaskFunction = function () {
let mjsStream: NodeJS.ReadableStream | undefined;
let jsStream: NodeJS.ReadableStream | undefined;
let dtsStream: NodeJS.ReadableStream | undefined;
const srcStream: NodeJS.ReadableStream = gulp
.src(resolved.absScripts, {base: options.srcDir})
.pipe(gulpSourceMaps.init());
interface CompiledStream {
js: NodeJS.ReadableStream;
dts: NodeJS.ReadableStream;
}
const reporter: TypescriptReporter = new TypescriptReporter(throwOnError);
// TODO: update type definitions of `gulp-sourcemaps`
const writeSourceMapsOptions: gulpSourceMaps.WriteOptions = <any> {
sourceRoot: (file: any /* VinylFile */): string => {
return posixPath.relative(posixPath.dirname(file.relative), "");
},
};
if (options.outModules === OutModules.Js) {
const compiledStream: CompiledStream = srcStream.pipe(gulpTypescript(tscOptions, reporter));
jsStream = compiledStream.js
.pipe(gulpSourceMaps.write(writeSourceMapsOptions));
dtsStream = compiledStream.dts;
} else { // Mjs or Both
const mjsOptions: CompilerOptionsJson = {...tscOptions, module: "es2015"};
const compiledStream: CompiledStream = srcStream.pipe(gulpTypescript(mjsOptions, reporter));
mjsStream = compiledStream.js
.pipe(gulpSourceMaps.write(writeSourceMapsOptions))
.pipe(gulpRename({extname: ".mjs"}));
dtsStream = compiledStream.dts;
if (options.outModules === OutModules.Both) {
jsStream = srcStream
.pipe(gulpTypescript(tscOptions, reporter))
.js
.pipe(gulpSourceMaps.write(writeSourceMapsOptions));
}
}
return merge([dtsStream, jsStream, mjsStream].filter(x => x !== undefined) as NodeJS.ReadableStream[])
.pipe(gulp.dest(options.buildDir));
};
task.displayName = "_build:scripts";
return task;
}
export function getBuildTypescriptWatchTask(gulp: Gulp, options: TypescriptConfig): () => FSWatcher {
return (): FSWatcher => {
const buildTask: TaskFunction = getBuildTypescriptTask(gulp, options, false);
const resolved: ResolvedTsLocations = resolveTsLocations(options);
return gulp.watch(resolved.absScripts, {cwd: options.srcDir}, buildTask) as FSWatcher;
};
}
export function getBuildTypescriptWatcher(gulp: Gulp, options: TypescriptConfig): FSWatcher {
return getBuildTypescriptWatchTask(gulp, options)();
}