Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.

Commit 1b33eba

Browse files
committed
Internal only refactoring
PiperOrigin-RevId: 221698301
1 parent 9ab2638 commit 1b33eba

File tree

6 files changed

+422
-54
lines changed

6 files changed

+422
-54
lines changed

examples/googmodule/a.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const a: number = 1;
1+
const a: number = 1;

internal/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ jasmine_node_test(
107107
srcs = [],
108108
deps = [
109109
":test_lib",
110+
"@npm//bytebuffer",
110111
"@npm//jasmine",
112+
"@npm//protobufjs",
113+
"@npm//source-map",
111114
"@npm//typescript",
112115
],
113116
)

internal/tsc_wrapped/tsc_wrapped.ts

Lines changed: 120 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as fs from 'fs';
12
import * as path from 'path';
23
import * as tsickle from 'tsickle';
34
import * as ts from 'typescript';
@@ -7,6 +8,7 @@ import {PLUGIN as bazelConformancePlugin} from '../tsetse/runner';
78
import {CachedFileLoader, FileLoader, ProgramAndFileCache, UncachedFileLoader} from './cache';
89
import {CompilerHost} from './compiler_host';
910
import * as bazelDiagnostics from './diagnostics';
11+
import {constructManifest} from './manifest';
1012
import * as perfTrace from './perf_trace';
1113
import {PLUGIN as strictDepsPlugin} from './strict_deps';
1214
import {BazelOptions, parseTsconfig, resolveNormalizedPath} from './tsconfig';
@@ -200,50 +202,135 @@ function runFromOptions(
200202
cache.putProgram(bazelOpts.target, program);
201203

202204

203-
const compilationTargets =
204-
program.getSourceFiles().filter(f => isCompilationTarget(bazelOpts, f));
205-
const emitResults: ts.EmitResult[] = [];
206-
const diagnostics: ts.Diagnostic[] = [];
207-
if (bazelOpts.tsickle) {
208-
// The 'tsickle' import above is only used in type positions, so it won't
209-
// result in a runtime dependency on tsickle.
210-
// If the user requests the tsickle emit, then we dynamically require it
211-
// here for use at runtime.
212-
let optTsickle: typeof tsickle;
213-
try {
214-
// tslint:disable-next-line:no-require-imports dependency on tsickle only
215-
// if requested
216-
optTsickle = require('tsickle');
217-
} catch {
218-
throw new Error(
219-
'When setting bazelOpts { tsickle: true }, ' +
220-
'you must also add a devDependency on the tsickle npm package');
221-
}
222-
for (const sf of compilationTargets) {
223-
emitResults.push(optTsickle.emitWithTsickle(
224-
program, compilerHost, compilerHost, options, sf));
225-
}
226-
diagnostics.push(
227-
...optTsickle.mergeEmitResults(emitResults as tsickle.EmitResult[])
228-
.diagnostics);
229-
} else {
230-
for (const sf of compilationTargets) {
231-
emitResults.push(program.emit(sf));
232-
}
205+
const compilationTargets = program.getSourceFiles().filter(
206+
fileName => isCompilationTarget(bazelOpts, fileName));
233207

234-
for (const d of emitResults) {
235-
diagnostics.push(...d.diagnostics);
236-
}
208+
let diagnostics: ts.Diagnostic[] = [];
209+
let useTsickleEmit = bazelOpts.tsickle;
210+
if (useTsickleEmit) {
211+
diagnostics = emitWithTsickle(
212+
program, compilerHost, compilationTargets, options, bazelOpts);
213+
} else {
214+
diagnostics = emitWithTypescript(program, compilationTargets);
237215
}
216+
238217
if (diagnostics.length > 0) {
239218
console.error(bazelDiagnostics.format(bazelOpts.target, diagnostics));
219+
debug('compilation failed at', new Error().stack!);
240220
return false;
241221
}
242222

243223
cache.printStats();
244224
return true;
245225
}
246226

227+
function emitWithTypescript(
228+
program: ts.Program, compilationTargets: ts.SourceFile[]): ts.Diagnostic[] {
229+
const diagnostics: ts.Diagnostic[] = [];
230+
for (const sf of compilationTargets) {
231+
const result = program.emit(sf);
232+
diagnostics.push(...result.diagnostics);
233+
}
234+
return diagnostics;
235+
}
236+
237+
function emitWithTsickle(
238+
program: ts.Program, compilerHost: CompilerHost,
239+
compilationTargets: ts.SourceFile[], options: ts.CompilerOptions,
240+
bazelOpts: BazelOptions): ts.Diagnostic[] {
241+
const emitResults: tsickle.EmitResult[] = [];
242+
const diagnostics: ts.Diagnostic[] = [];
243+
// The 'tsickle' import above is only used in type positions, so it won't
244+
// result in a runtime dependency on tsickle.
245+
// If the user requests the tsickle emit, then we dynamically require it
246+
// here for use at runtime.
247+
let optTsickle: typeof tsickle;
248+
try {
249+
// tslint:disable-next-line:no-require-imports
250+
optTsickle = require('tsickle');
251+
} catch (e) {
252+
if (e.code !== 'MODULE_NOT_FOUND') {
253+
throw e;
254+
}
255+
throw new Error(
256+
'When setting bazelOpts { tsickle: true }, ' +
257+
'you must also add a devDependency on the tsickle npm package');
258+
}
259+
perfTrace.wrap('emit', () => {
260+
for (const sf of compilationTargets) {
261+
perfTrace.wrap(`emit ${sf.fileName}`, () => {
262+
emitResults.push(optTsickle.emitWithTsickle(
263+
program, compilerHost, compilerHost, options, sf));
264+
});
265+
}
266+
});
267+
const emitResult = optTsickle.mergeEmitResults(emitResults);
268+
diagnostics.push(...emitResult.diagnostics);
269+
270+
// If tsickle reported diagnostics, don't produce externs or manifest outputs.
271+
if (diagnostics.length > 0) {
272+
return diagnostics;
273+
}
274+
275+
let externs = '/** @externs */\n' +
276+
'// generating externs was disabled using generate_externs=False\n';
277+
if (bazelOpts.tsickleGenerateExterns) {
278+
externs =
279+
optTsickle.getGeneratedExterns(emitResult.externs, options.rootDir!);
280+
}
281+
282+
if (bazelOpts.tsickleExternsPath) {
283+
// Note: when tsickleExternsPath is provided, we always write a file as a
284+
// marker that compilation succeeded, even if it's empty (just containing an
285+
// @externs).
286+
fs.writeFileSync(bazelOpts.tsickleExternsPath, externs);
287+
288+
// When generating externs, generate an externs file for each of the input
289+
// .d.ts files.
290+
if (bazelOpts.tsickleGenerateExterns &&
291+
compilerHost.provideExternalModuleDtsNamespace) {
292+
for (const extern of compilationTargets) {
293+
if (!extern.isDeclarationFile) continue;
294+
const outputBaseDir = options.outDir!;
295+
const relativeOutputPath =
296+
compilerHost.relativeOutputPath(extern.fileName);
297+
mkdirp(outputBaseDir, path.dirname(relativeOutputPath));
298+
const outputPath = path.join(outputBaseDir, relativeOutputPath);
299+
const moduleName = compilerHost.pathToModuleName('', extern.fileName);
300+
fs.writeFileSync(
301+
outputPath,
302+
`goog.module('${moduleName}');\n` +
303+
`// Export an empty object of unknown type to allow imports.\n` +
304+
`// TODO: use typeof once available\n` +
305+
`exports = /** @type {?} */ ({});\n`);
306+
}
307+
}
308+
}
309+
310+
if (bazelOpts.manifest) {
311+
perfTrace.wrap('manifest', () => {
312+
const manifest =
313+
constructManifest(emitResult.modulesManifest, compilerHost);
314+
fs.writeFileSync(bazelOpts.manifest, manifest);
315+
});
316+
}
317+
318+
return diagnostics;
319+
}
320+
321+
/**
322+
* Creates directories subdir (a slash separated relative path) starting from
323+
* base.
324+
*/
325+
function mkdirp(base: string, subdir: string) {
326+
const steps = subdir.split(path.sep);
327+
let current = base;
328+
for (let i = 0; i < steps.length; i++) {
329+
current = path.join(current, steps[i]);
330+
if (!fs.existsSync(current)) fs.mkdirSync(current);
331+
}
332+
}
333+
247334

248335
if (require.main === module) {
249336
// Do not call process.exit(), as that terminates the binary before

0 commit comments

Comments
 (0)