feat(ivy): first steps towards ngtsc mode (#23455)
This commit adds a new compiler pipeline that isn't dependent on global analysis, referred to as 'ngtsc'. This new compiler is accessed by running ngc with "enableIvy" set to "ngtsc". It reuses the same initialization logic but creates a new implementation of Program which does not perform the global-level analysis that AngularCompilerProgram does. It will be the foundation for the production Ivy compiler. PR Close #23455
This commit is contained in:

committed by
Igor Minar

parent
f567e1898f
commit
ab5bc42da0
@ -184,7 +184,7 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
enableIvy?: boolean;
|
||||
enableIvy?: boolean|'ngtsc';
|
||||
|
||||
/** @internal */
|
||||
collectAllErrors?: boolean;
|
||||
|
@ -12,6 +12,7 @@ import * as ts from 'typescript';
|
||||
|
||||
import {TypeCheckHost} from '../diagnostics/translate_diagnostics';
|
||||
import {METADATA_VERSION, ModuleMetadata} from '../metadata/index';
|
||||
import {NgtscCompilerHost} from '../ngtsc/compiler_host';
|
||||
|
||||
import {CompilerHost, CompilerOptions, LibrarySummary} from './api';
|
||||
import {MetadataReaderHost, createMetadataReaderCache, readMetadata} from './metadata_reader';
|
||||
@ -23,6 +24,9 @@ const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||
export function createCompilerHost(
|
||||
{options, tsHost = ts.createCompilerHost(options, true)}:
|
||||
{options: CompilerOptions, tsHost?: ts.CompilerHost}): CompilerHost {
|
||||
if (options.enableIvy) {
|
||||
return new NgtscCompilerHost(tsHost);
|
||||
}
|
||||
return tsHost;
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ParseSourceFile, ParseSourceSpan, PartialModule, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler';
|
||||
import {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ParseSourceFile, ParseSourceSpan, PartialModule, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {error} from './util';
|
||||
|
||||
export interface Node { sourceSpan: ParseSourceSpan|null; }
|
||||
@ -20,7 +21,7 @@ const _VALID_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
|
||||
export class TypeScriptNodeEmitter {
|
||||
updateSourceFile(sourceFile: ts.SourceFile, stmts: Statement[], preamble?: string):
|
||||
[ts.SourceFile, Map<ts.Node, Node>] {
|
||||
const converter = new _NodeEmitterVisitor();
|
||||
const converter = new NodeEmitterVisitor();
|
||||
// [].concat flattens the result so that each `visit...` method can also return an array of
|
||||
// stmts.
|
||||
const statements: any[] = [].concat(
|
||||
@ -62,7 +63,7 @@ export class TypeScriptNodeEmitter {
|
||||
export function updateSourceFile(
|
||||
sourceFile: ts.SourceFile, module: PartialModule,
|
||||
context: ts.TransformationContext): [ts.SourceFile, Map<ts.Node, Node>] {
|
||||
const converter = new _NodeEmitterVisitor();
|
||||
const converter = new NodeEmitterVisitor();
|
||||
converter.loadExportedVariableIdentifiers(sourceFile);
|
||||
|
||||
const prefixStatements = module.statements.filter(statement => !(statement instanceof ClassStmt));
|
||||
@ -148,7 +149,7 @@ function firstAfter<T>(a: T[], predicate: (value: T) => boolean) {
|
||||
// A recorded node is a subtype of the node that is marked as being recorded. This is used
|
||||
// to ensure that NodeEmitterVisitor.record has been called on all nodes returned by the
|
||||
// NodeEmitterVisitor
|
||||
type RecordedNode<T extends ts.Node = ts.Node> = (T & { __recorded: any; }) | null;
|
||||
export type RecordedNode<T extends ts.Node = ts.Node> = (T & { __recorded: any;}) | null;
|
||||
|
||||
function escapeLiteral(value: string): string {
|
||||
return value.replace(/(\"|\\)/g, '\\$1').replace(/(\n)|(\r)/g, function(v, n, r) {
|
||||
@ -183,7 +184,7 @@ function isExportTypeStatement(statement: ts.Statement): boolean {
|
||||
/**
|
||||
* Visits an output ast and produces the corresponding TypeScript synthetic nodes.
|
||||
*/
|
||||
class _NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
private _nodeMap = new Map<ts.Node, Node>();
|
||||
private _importsWithPrefixes = new Map<string, string>();
|
||||
private _reexports = new Map<string, {name: string, as: string}[]>();
|
||||
@ -461,6 +462,9 @@ class _NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor {
|
||||
return commentStmt;
|
||||
}
|
||||
|
||||
// ExpressionVisitor
|
||||
visitWrappedNodeExpr(expr: WrappedNodeExpr<any>) { return this.record(expr, expr.node); }
|
||||
|
||||
// ExpressionVisitor
|
||||
visitReadVarExpr(expr: ReadVarExpr) {
|
||||
switch (expr.builtin) {
|
||||
|
@ -15,6 +15,7 @@ import * as ts from 'typescript';
|
||||
import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics';
|
||||
import {compareVersions} from '../diagnostics/typescript_version';
|
||||
import {MetadataCollector, ModuleMetadata, createBundleIndexHost} from '../metadata/index';
|
||||
import {NgtscProgram} from '../ngtsc/program';
|
||||
|
||||
import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, DiagnosticMessageChain, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback, TsMergeEmitResultsCallback} from './api';
|
||||
import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host';
|
||||
@ -286,6 +287,9 @@ class AngularCompilerProgram implements Program {
|
||||
emitCallback?: TsEmitCallback,
|
||||
mergeEmitResultsCallback?: TsMergeEmitResultsCallback,
|
||||
} = {}): ts.EmitResult {
|
||||
if (this.options.enableIvy === 'ngtsc') {
|
||||
throw new Error('Cannot run legacy compiler in ngtsc mode');
|
||||
}
|
||||
return this.options.enableIvy === true ? this._emitRender3(parameters) :
|
||||
this._emitRender2(parameters);
|
||||
}
|
||||
@ -903,6 +907,9 @@ export function createProgram({rootNames, options, host, oldProgram}: {
|
||||
options: CompilerOptions,
|
||||
host: CompilerHost, oldProgram?: Program
|
||||
}): Program {
|
||||
if (options.enableIvy === 'ngtsc') {
|
||||
return new NgtscProgram(rootNames, options, host, oldProgram);
|
||||
}
|
||||
return new AngularCompilerProgram(rootNames, options, host, oldProgram);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user