parent
04997c8418
commit
c76da27240
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, StubEmitFlags, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler';
|
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
@ -63,7 +63,6 @@ class AngularCompilerProgram implements Program {
|
|||||||
({content, fileName}) => this.summariesFromPreviousCompilations.set(fileName, content));
|
({content, fileName}) => this.summariesFromPreviousCompilations.set(fileName, content));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rootNames = rootNames = rootNames.filter(r => !GENERATED_FILES.test(r));
|
|
||||||
if (options.flatModuleOutFile) {
|
if (options.flatModuleOutFile) {
|
||||||
const {host: bundleHost, indexName, errors} = createBundleIndexHost(options, rootNames, host);
|
const {host: bundleHost, indexName, errors} = createBundleIndexHost(options, rootNames, host);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
@ -133,14 +132,15 @@ class AngularCompilerProgram implements Program {
|
|||||||
if (this._analyzedModules) {
|
if (this._analyzedModules) {
|
||||||
throw new Error('Angular structure already loaded');
|
throw new Error('Angular structure already loaded');
|
||||||
}
|
}
|
||||||
const {tmpProgram, analyzedFiles, hostAdapter} = this._createProgramWithBasicStubs();
|
const {tmpProgram, analyzedFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs();
|
||||||
return this._compiler.loadFilesAsync(analyzedFiles)
|
return this._compiler.loadFilesAsync(analyzedFiles)
|
||||||
.catch(this.catchAnalysisError.bind(this))
|
.catch(this.catchAnalysisError.bind(this))
|
||||||
.then(analyzedModules => {
|
.then(analyzedModules => {
|
||||||
if (this._analyzedModules) {
|
if (this._analyzedModules) {
|
||||||
throw new Error('Angular structure loaded both synchronously and asynchronsly');
|
throw new Error('Angular structure loaded both synchronously and asynchronsly');
|
||||||
}
|
}
|
||||||
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter);
|
this._updateProgramWithTypeCheckStubs(
|
||||||
|
tmpProgram, analyzedModules, hostAdapter, rootNames);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ class AngularCompilerProgram implements Program {
|
|||||||
program: this.tsProgram,
|
program: this.tsProgram,
|
||||||
host: this.host,
|
host: this.host,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
writeFile: createWriteFileCallback(emitFlags, this.host, outSrcMapping),
|
writeFile: createWriteFileCallback(genFiles, this.host, outSrcMapping),
|
||||||
emitOnlyDtsFiles: (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS,
|
emitOnlyDtsFiles: (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS,
|
||||||
customTransformers: this.calculateTransforms(genFiles, customTransformers)
|
customTransformers: this.calculateTransforms(genFiles, customTransformers)
|
||||||
});
|
});
|
||||||
@ -291,20 +291,21 @@ class AngularCompilerProgram implements Program {
|
|||||||
if (this._analyzedModules) {
|
if (this._analyzedModules) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const {tmpProgram, analyzedFiles, hostAdapter} = this._createProgramWithBasicStubs();
|
const {tmpProgram, analyzedFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs();
|
||||||
let analyzedModules: NgAnalyzedModules;
|
let analyzedModules: NgAnalyzedModules;
|
||||||
try {
|
try {
|
||||||
analyzedModules = this._compiler.loadFilesSync(analyzedFiles);
|
analyzedModules = this._compiler.loadFilesSync(analyzedFiles);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
analyzedModules = this.catchAnalysisError(e);
|
analyzedModules = this.catchAnalysisError(e);
|
||||||
}
|
}
|
||||||
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter);
|
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter, rootNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createProgramWithBasicStubs(): {
|
private _createProgramWithBasicStubs(): {
|
||||||
tmpProgram: ts.Program,
|
tmpProgram: ts.Program,
|
||||||
analyzedFiles: NgAnalyzedFile[],
|
analyzedFiles: NgAnalyzedFile[],
|
||||||
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter
|
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter,
|
||||||
|
rootNames: string[],
|
||||||
} {
|
} {
|
||||||
if (this._analyzedModules) {
|
if (this._analyzedModules) {
|
||||||
throw new Error(`Internal Error: already initalized!`);
|
throw new Error(`Internal Error: already initalized!`);
|
||||||
@ -330,17 +331,31 @@ class AngularCompilerProgram implements Program {
|
|||||||
this._typeCheckHost = hostAdapter;
|
this._typeCheckHost = hostAdapter;
|
||||||
this._structuralDiagnostics = [];
|
this._structuralDiagnostics = [];
|
||||||
|
|
||||||
const tmpProgram = ts.createProgram(this.rootNames, this.options, hostAdapter, oldTsProgram);
|
let rootNames =
|
||||||
return {tmpProgram, analyzedFiles, hostAdapter};
|
this.rootNames.filter(fn => !GENERATED_FILES.test(fn) || !hostAdapter.isSourceFile(fn));
|
||||||
|
if (this.options.noResolve) {
|
||||||
|
this.rootNames.forEach(rootName => {
|
||||||
|
const sf =
|
||||||
|
hostAdapter.getSourceFile(rootName, this.options.target || ts.ScriptTarget.Latest);
|
||||||
|
sf.referencedFiles.forEach((fileRef) => {
|
||||||
|
if (GENERATED_FILES.test(fileRef.fileName)) {
|
||||||
|
rootNames.push(fileRef.fileName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tmpProgram = ts.createProgram(rootNames, this.options, hostAdapter, oldTsProgram);
|
||||||
|
return {tmpProgram, analyzedFiles, hostAdapter, rootNames};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateProgramWithTypeCheckStubs(
|
private _updateProgramWithTypeCheckStubs(
|
||||||
tmpProgram: ts.Program, analyzedModules: NgAnalyzedModules,
|
tmpProgram: ts.Program, analyzedModules: NgAnalyzedModules,
|
||||||
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter) {
|
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter, rootNames: string[]) {
|
||||||
this._analyzedModules = analyzedModules;
|
this._analyzedModules = analyzedModules;
|
||||||
const genFiles = this._compiler.emitTypeCheckStubs(analyzedModules);
|
const genFiles = this._compiler.emitTypeCheckStubs(analyzedModules);
|
||||||
genFiles.forEach(gf => hostAdapter.updateGeneratedFile(gf));
|
genFiles.forEach(gf => hostAdapter.updateGeneratedFile(gf));
|
||||||
this._tsProgram = ts.createProgram(this.rootNames, this.options, hostAdapter, tmpProgram);
|
this._tsProgram = ts.createProgram(rootNames, this.options, hostAdapter, tmpProgram);
|
||||||
// Note: the new ts program should be completely reusable by TypeScript as:
|
// Note: the new ts program should be completely reusable by TypeScript as:
|
||||||
// - we cache all the files in the hostAdapter
|
// - we cache all the files in the hostAdapter
|
||||||
// - new new stubs use the exactly same imports/exports as the old once (we assert that in
|
// - new new stubs use the exactly same imports/exports as the old once (we assert that in
|
||||||
@ -453,17 +468,24 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createWriteFileCallback(
|
function createWriteFileCallback(
|
||||||
emitFlags: EmitFlags, host: ts.CompilerHost,
|
generatedFiles: GeneratedFile[], host: ts.CompilerHost,
|
||||||
outSrcMapping: Array<{sourceFile: ts.SourceFile, outFileName: string}>) {
|
outSrcMapping: Array<{sourceFile: ts.SourceFile, outFileName: string}>) {
|
||||||
|
const genFileByFileName = new Map<string, GeneratedFile>();
|
||||||
|
generatedFiles.forEach(genFile => genFileByFileName.set(genFile.genFileUrl, genFile));
|
||||||
return (fileName: string, data: string, writeByteOrderMark: boolean,
|
return (fileName: string, data: string, writeByteOrderMark: boolean,
|
||||||
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
||||||
const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null;
|
const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null;
|
||||||
const isGenerated = GENERATED_FILES.test(fileName);
|
|
||||||
if (sourceFile) {
|
if (sourceFile) {
|
||||||
outSrcMapping.push({outFileName: fileName, sourceFile});
|
outSrcMapping.push({outFileName: fileName, sourceFile});
|
||||||
}
|
}
|
||||||
if (isGenerated && !(emitFlags & EmitFlags.Codegen)) {
|
const isGenerated = GENERATED_FILES.test(fileName);
|
||||||
return;
|
if (isGenerated && sourceFile) {
|
||||||
|
// Filter out generated files for which we didn't generate code.
|
||||||
|
// This can happen as the stub caclulation is not completely exact.
|
||||||
|
const genFile = genFileByFileName.get(sourceFile.fileName);
|
||||||
|
if (!genFile || !genFile.stmts || genFile.stmts.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||||
};
|
};
|
||||||
|
@ -208,4 +208,28 @@ describe('ng program', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work with noResolve', () => {
|
||||||
|
// create a temporary ts program to get the list of all files from angular...
|
||||||
|
testSupport.writeFiles({
|
||||||
|
'src/main.ts': createModuleAndCompSource('main'),
|
||||||
|
});
|
||||||
|
const preOptions = testSupport.createCompilerOptions();
|
||||||
|
const preHost = ts.createCompilerHost(preOptions);
|
||||||
|
// don't resolve symlinks
|
||||||
|
preHost.realpath = (f) => f;
|
||||||
|
const preProgram =
|
||||||
|
ts.createProgram([path.resolve(testSupport.basePath, 'src/main.ts')], preOptions, preHost);
|
||||||
|
const allRootNames = preProgram.getSourceFiles().map(sf => sf.fileName);
|
||||||
|
|
||||||
|
// now do the actual test with noResolve
|
||||||
|
const options = testSupport.createCompilerOptions({noResolve: true});
|
||||||
|
const host = ng.createCompilerHost({options});
|
||||||
|
const program = ng.createProgram({rootNames: allRootNames, options, host});
|
||||||
|
expectNoDiagnosticsInProgram(options, program);
|
||||||
|
program.emit();
|
||||||
|
|
||||||
|
testSupport.shouldExist('built/src/main.ngfactory.js');
|
||||||
|
testSupport.shouldExist('built/src/main.ngfactory.d.ts');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user