Skip to content

Commit 36ff1f5

Browse files
authored
Merge pull request #577 from ivogabe/declaration
Source maps for declaration files (continuation of 575)
2 parents ff940bb + fd3239c commit 36ff1f5

File tree

129 files changed

+3648
-2068
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+3648
-2068
lines changed

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@
55
[submodule "typescript/2.3"]
66
path = typescript/2.3
77
url = https://github.com/Microsoft/TypeScript.git
8+
[submodule "2.9"]
9+
path = 2.9
10+
url = https://github.com/Microsoft/TypeScript
11+
[submodule "typescript/2.9"]
12+
path = typescript/2.9
13+
url = https://github.com/Microsoft/TypeScript

.vscode/tasks.json

Lines changed: 0 additions & 22 deletions
This file was deleted.

gulpfile.js

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const diff = require('gulp-diff');
1111
const tsVersions = {
1212
dev: './typescript/dev',
1313
release23: './typescript/2.3',
14+
release29: './typescript/2.9'
1415
};
1516

1617
function findTSDefinition(location) {
@@ -35,9 +36,9 @@ const tests = fs.readdirSync(path.join(__dirname, 'test')).filter(function(dir)
3536
});
3637

3738
// Clean
38-
gulp.task('clean', function(cb) {
39+
function clean(cb) {
3940
rimraf(paths.releaseBeta, cb);
40-
});
41+
}
4142
gulp.task('clean-test', function(cb) {
4243
rimraf('test/output', cb);
4344
});
@@ -46,35 +47,36 @@ gulp.task('clean-release', function(cb) {
4647
});
4748

4849
// Compile sources
49-
gulp.task('scripts', ['clean'], function() {
50+
const compile = gulp.series(clean, function compile() {
5051
return gulp.src(paths.scripts.concat(paths.definitionTypeScript))
5152
.pipe(tsProject())
5253
.pipe(gulp.dest(paths.releaseBeta));
5354
});
5455

56+
5557
// Type checking against multiple versions of TypeScript
56-
gulp.task('typecheck-dev', function() {
58+
function typecheckDev() {
5759
return gulp.src(paths.scripts.concat([
5860
'!definitions/typescript.d.ts',
5961
findTSDefinition(tsVersions.dev)
6062
])).pipe(createProject({ noEmit: true })());
61-
});
62-
63-
gulp.task('typecheck-2.3', function() {
63+
}
64+
function typecheck2_3() {
6465
return gulp.src(paths.scripts.concat([
6566
'!definitions/typescript.d.ts',
6667
findTSDefinition(tsVersions.release23)
6768
])).pipe(createProject({ noEmit: true })());
68-
});
69+
}
6970

70-
gulp.task('typecheck', ['typecheck-dev', 'typecheck-2.3']);
71+
const typecheck = gulp.parallel(typecheckDev, typecheck2_3);
7172

7273
// Tests
7374

7475
// We run every test on multiple typescript versions:
7576
const libs = [
7677
['2.7', undefined],
7778
['2.3', require(tsVersions.release23)],
79+
['2.9', require(tsVersions.release29)],
7880
['dev', require(tsVersions.dev)]
7981
];
8082

@@ -128,18 +130,18 @@ async function runTest(name) {
128130
}));
129131
}
130132

131-
gulp.task('test-run', ['clean-test', 'scripts'], async function() {
133+
gulp.task('test-run', gulp.series('clean-test', async function testRun() {
132134
fs.mkdirSync('test/output/');
133135
for (const testName of tests) {
134136
await runTest(testName);
135137
}
136-
});
138+
}));
137139

138140
/**
139141
* Executes all the test tasks and then compares their output against the expected output (defined in
140142
* `test/baseline`).
141143
*/
142-
gulp.task('test', ['test-run'], function() {
144+
gulp.task('test', gulp.series('test-run', function testVerify() {
143145
let failed = false;
144146
function onError(error) {
145147
failed = true;
@@ -155,21 +157,23 @@ gulp.task('test', ['test-run'], function() {
155157
throw new Error('Tests failed');
156158
}
157159
});
158-
});
160+
}));
159161

160162
// Accept new baselines
161-
gulp.task('test-baselines-accept', function(cb) {
163+
gulp.task('test-baselines-accept', function testBaselinesAccept(cb) {
162164
rimraf('test/baselines', function() {
163165
gulp.src('test/output/**').pipe(gulp.dest('test/baselines')).on('finish', cb);
164166
});
165167
});
166168

167-
gulp.task('release', function() {
169+
gulp.task('release', function release() {
168170
return gulp.src(paths.releaseBeta + '/**').pipe(gulp.dest(paths.release));
169171
});
170172

171-
gulp.task('watch', ['scripts'], function() {
172-
gulp.watch(paths.scripts, ['scripts']);
173-
});
173+
// Expose main tasks
174+
gulp.task('scripts', compile);
175+
gulp.task('default', gulp.series(compile, gulp.parallel(typecheck, 'test')));
174176

175-
gulp.task('default', ['scripts', 'typecheck', 'test']);
177+
gulp.task('watch', gulp.series('scripts', function watch() {
178+
gulp.watch(paths.scripts, compile);
179+
}));

lib/compiler.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ interface OutputFile {
1818

1919
jsFileName?: string;
2020
dtsFileName?: string;
21+
dtsMapFileName?: string;
2122
jsContent?: string;
2223
jsMapContent?: string;
2324
dtsContent?: string;
25+
dtsMapContent?: string;
2426
}
2527

2628
/**
@@ -125,13 +127,17 @@ export class ProjectCompiler implements ICompiler {
125127
}
126128

127129
private attachContentToFile(file: OutputFile, fileName: string, content: string) {
128-
const [, extension] = utils.splitExtension(fileName, ['d.ts']);
130+
const [, extension] = utils.splitExtension(fileName, ['d.ts', 'd.ts.map']);
129131
switch (extension) {
130132
case 'js':
131133
case 'jsx':
132134
file.jsFileName = fileName;
133135
file.jsContent = content;
134136
break;
137+
case 'd.ts.map':
138+
file.dtsMapFileName = fileName;
139+
file.dtsMapContent = content;
140+
break;
135141
case 'd.ts':
136142
file.dtsFileName = fileName;
137143
file.dtsContent = content;
@@ -149,7 +155,7 @@ export class ProjectCompiler implements ICompiler {
149155

150156
result.emitSkipped = emitOutput.emitSkipped;
151157
}
152-
private emitFile({ file, jsFileName, dtsFileName, jsContent, dtsContent, jsMapContent }: OutputFile, currentDirectory: string) {
158+
private emitFile({ file, jsFileName, dtsFileName, dtsMapFileName, jsContent, dtsContent, dtsMapContent, jsMapContent }: OutputFile, currentDirectory: string) {
153159
if (!jsFileName) return;
154160

155161
let base: string;
@@ -184,7 +190,7 @@ export class ProjectCompiler implements ICompiler {
184190
this.project.output.writeJs(base, jsFileName, jsContent, jsMapContent, file ? file.gulp.cwd : currentDirectory, file);
185191
}
186192
if (dtsContent !== undefined) {
187-
this.project.output.writeDts(baseDeclarations, dtsFileName, dtsContent, file ? file.gulp.cwd : currentDirectory);
193+
this.project.output.writeDts(baseDeclarations, dtsFileName, dtsContent, dtsMapContent, file ? file.gulp.cwd : currentDirectory, file);
188194
}
189195
}
190196

@@ -270,7 +276,7 @@ export class FileCompiler implements ICompiler {
270276

271277
mapString = mapString.substring(start.length);
272278

273-
let map: RawSourceMap = JSON.parse(new Buffer(mapString, 'base64').toString());
279+
let map: RawSourceMap = JSON.parse(Buffer.from(mapString, 'base64').toString());
274280
// TODO: Set paths correctly
275281
// map.sourceRoot = path.resolve(file.gulp.cwd, file.gulp.base);
276282
// map.sources[0] = path.relative(map.sourceRoot, file.gulp.path);

lib/main.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,18 @@ function checkAndNormalizeSettings(settings: compile.Settings): compile.Settings
7070
return standardSettings;
7171
}
7272

73-
function normalizeCompilerOptions(options: ts.CompilerOptions): void {
73+
function normalizeCompilerOptions(options: ts.CompilerOptions, typescript: typeof ts): void {
7474
options.sourceMap = true;
7575
(options as any).suppressOutputPathCheck = true;
7676
options.inlineSourceMap = false;
7777
options.sourceRoot = undefined;
7878
options.inlineSources = false;
79+
80+
// For TS >=2.9, we set `declarationMap` to true, if `declaration` is set.
81+
// We check for this version by checking whether `createFileLevelUniqueName` exists.
82+
if ("createFileLevelUniqueName" in typescript && options.declaration && !options.isolatedModules) {
83+
options.declarationMap = true;
84+
}
7985
}
8086

8187
function reportErrors(errors: ts.Diagnostic[], typescript: typeof ts, ignore: number[] = []): void {
@@ -196,7 +202,7 @@ module compile {
196202
}
197203
}
198204

199-
normalizeCompilerOptions(compilerOptions);
205+
normalizeCompilerOptions(compilerOptions, typescript);
200206
const project = _project.setupProject(projectDirectory, tsConfigFileName, rawConfig, tsConfigContent, compilerOptions, typescript);
201207

202208
return project;

lib/output.ts

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,31 +25,50 @@ export class Output {
2525
// .d.ts files
2626
streamDts: stream.Readable;
2727

28+
// Number of pending IO operatrions
29+
private pendingIO = 0;
30+
2831
writeJs(base: string, fileName: string, content: string, sourceMapContent: string, cwd: string, original: input.File) {
2932
const file = new VinylFile({
3033
path: fileName,
31-
contents: new Buffer(content),
34+
contents: Buffer.from(content),
3235
cwd,
3336
base
3437
});
35-
const appliedSourceMap = this.applySourceMap(sourceMapContent, original, file);
36-
if (appliedSourceMap) file.sourceMap = JSON.parse(appliedSourceMap);
37-
this.streamFull.push(file);
38-
this.streamJs.push(file);
38+
39+
this.pendingIO++;
40+
41+
this.applySourceMap(sourceMapContent, original, file).then(appliedSourceMap => {
42+
if (appliedSourceMap) file.sourceMap = JSON.parse(appliedSourceMap);
43+
this.streamFull.push(file);
44+
this.streamJs.push(file);
45+
46+
this.pendingIO--;
47+
this.mightFinish();
48+
});
3949
}
4050

41-
writeDts(base: string, fileName: string, content: string, cwd: string) {
51+
async writeDts(base: string, fileName: string, content: string, declarationMapContent: string, cwd: string, original: input.File) {
4252
const file = new VinylFile({
4353
path: fileName,
44-
contents: new Buffer(content),
54+
contents: Buffer.from(content),
4555
cwd,
4656
base
4757
});
48-
this.streamFull.push(file);
49-
this.streamDts.push(file);
58+
59+
this.pendingIO++;
60+
61+
this.applySourceMap(declarationMapContent, original, file).then(appliedSourceMap => {
62+
if (appliedSourceMap) file.sourceMap = JSON.parse(appliedSourceMap);
63+
this.streamFull.push(file);
64+
this.streamDts.push(file);
65+
66+
this.pendingIO--;
67+
this.mightFinish();
68+
});
5069
}
5170

52-
private applySourceMap(sourceMapContent: string, original: input.File, output: VinylFile) {
71+
private async applySourceMap(sourceMapContent: string, original: input.File, output: VinylFile) {
5372
if (sourceMapContent === undefined) return undefined;
5473

5574
const map = JSON.parse(sourceMapContent);
@@ -62,13 +81,13 @@ export class Output {
6281

6382
delete map.sourceRoot;
6483

65-
const generator = sourceMap.SourceMapGenerator.fromSourceMap(new sourceMap.SourceMapConsumer(map));
84+
const consumer = await new sourceMap.SourceMapConsumer(map);
85+
const generator = sourceMap.SourceMapGenerator.fromSourceMap(consumer);
6686

6787
const sourceMapOrigins = this.project.singleOutput
6888
? this.project.input.getFileNames(true).map(fName => this.project.input.getFile(fName))
6989
: [original];
7090

71-
7291
for (const sourceFile of sourceMapOrigins) {
7392
if (!sourceFile || !sourceFile.gulp || !sourceFile.gulp.sourceMap) continue;
7493

@@ -78,8 +97,9 @@ export class Output {
7897
// We should only apply the input mappings if the input mapping isn't empty,
7998
// since `generator.applySourceMap` has a really bad performance on big inputs.
8099
if (inputMap.mappings !== '') {
81-
const consumer = new sourceMap.SourceMapConsumer(inputMap);
82-
generator.applySourceMap(consumer);
100+
const inputConsumer = await new sourceMap.SourceMapConsumer(inputMap);
101+
generator.applySourceMap(inputConsumer);
102+
inputConsumer.destroy();
83103
}
84104

85105
if (!inputMap.sources || !inputMap.sourcesContent) continue;
@@ -89,6 +109,7 @@ export class Output {
89109
generator.setSourceContent(utils.forwardSlashes(relative), inputMap.sourcesContent[i]);
90110
}
91111
}
112+
consumer.destroy();
92113
return generator.toString();
93114

94115
function relativeToOutput(fileName: string) {
@@ -99,7 +120,18 @@ export class Output {
99120

100121
finish(result: reporter.CompilationResult) {
101122
this.result = result;
102-
if (this.project.reporter.finish) this.project.reporter.finish(result);
123+
124+
this.mightFinish();
125+
}
126+
127+
private mightFinish() {
128+
if (this.result === undefined || this.pendingIO !== 0) return;
129+
130+
if (this.project.reporter.finish) this.project.reporter.finish(this.result);
131+
132+
if (reporter.countErrors(this.result) !== 0) {
133+
this.streamFull.emit('error', new Error("TypeScript: Compilation failed"));
134+
}
103135

104136
this.streamFull.emit('finish');
105137
this.streamFull.push(null);
@@ -122,6 +154,5 @@ export class Output {
122154
// call reporter callback
123155
if (this.project.reporter.error) this.project.reporter.error(<reporter.TypeScriptError> error, this.project.typescript);
124156
// & emit the error on the stream.
125-
this.streamFull.emit('error', error);
126157
}
127158
}

lib/project.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,6 @@ class CompileStream extends stream.Duplex implements ICompileStream {
144144
super({objectMode: true});
145145

146146
this.project = project;
147-
148-
// Prevent "Unhandled stream error in pipe" when a compilation error occurs.
149-
this.on('error', () => {});
150147
}
151148

152149
private project: ProjectInfo;

lib/reporter.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ export interface Reporter {
5555
finish?: (results: CompilationResult) => void;
5656
}
5757

58+
export function countErrors(results: CompilationResult) {
59+
return results.transpileErrors
60+
+ results.optionsErrors
61+
+ results.syntaxErrors
62+
+ results.globalErrors
63+
+ results.semanticErrors
64+
+ results.declarationErrors
65+
+ results.emitErrors;
66+
}
67+
5868
function defaultFinishHandler(results: CompilationResult) {
5969
let hasError = false;
6070
const showErrorCount = (count: number, type: string) => {

lib/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"target": "ES5",
3+
"target": "es2015",
44
"module": "commonjs",
55
"noUnusedLocals": true,
66
"noImplicitAny": true,

0 commit comments

Comments
 (0)