refactor(compiler-cli): setup compilation mode to enable generating linker code (#38938)

This is a precursor to introducing the Angular linker. As an initial
step, a compiler option to configure the compilation mode is introduced.
This option is initially internal until the linker is considered ready.

PR Close #38938
This commit is contained in:
JoostK 2020-09-09 21:32:56 +02:00 committed by Joey Perrott
parent eec9f4a84e
commit 9d04b95166
15 changed files with 213 additions and 30 deletions

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript';
import {IncrementalBuild} from '../../../src/ngtsc/incremental/api'; import {IncrementalBuild} from '../../../src/ngtsc/incremental/api';
import {NOOP_PERF_RECORDER} from '../../../src/ngtsc/perf'; import {NOOP_PERF_RECORDER} from '../../../src/ngtsc/perf';
import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection';
import {DecoratorHandler, DtsTransformRegistry, HandlerFlags, Trait, TraitCompiler} from '../../../src/ngtsc/transform'; import {CompilationMode, DecoratorHandler, DtsTransformRegistry, HandlerFlags, Trait, TraitCompiler} from '../../../src/ngtsc/transform';
import {NgccReflectionHost} from '../host/ngcc_host'; import {NgccReflectionHost} from '../host/ngcc_host';
import {isDefined} from '../utils'; import {isDefined} from '../utils';
@ -26,7 +26,7 @@ export class NgccTraitCompiler extends TraitCompiler {
private ngccReflector: NgccReflectionHost) { private ngccReflector: NgccReflectionHost) {
super( super(
handlers, ngccReflector, NOOP_PERF_RECORDER, new NoIncrementalBuild(), handlers, ngccReflector, NOOP_PERF_RECORDER, new NoIncrementalBuild(),
/* compileNonExportedClasses */ true, new DtsTransformRegistry()); /* compileNonExportedClasses */ true, CompilationMode.FULL, new DtsTransformRegistry());
} }
get analyzedFiles(): ts.SourceFile[] { get analyzedFiles(): ts.SourceFile[] {

View File

@ -48,7 +48,7 @@ runInEachFileSystem(() => {
'analyze', 'analyze',
'register', 'register',
'resolve', 'resolve',
'compile', 'compileFull',
]); ]);
// Only detect the Component and Directive decorators // Only detect the Component and Directive decorators
handler.detect.and.callFake( handler.detect.and.callFake(
@ -95,7 +95,7 @@ runInEachFileSystem(() => {
}); });
// The "test" compilation result is just the name of the decorator being compiled // The "test" compilation result is just the name of the decorator being compiled
// (suffixed with `(compiled)`) // (suffixed with `(compiled)`)
(handler.compile as any).and.callFake((decl: ts.Declaration, analysis: any) => { (handler.compileFull as any).and.callFake((decl: ts.Declaration, analysis: any) => {
logs.push(`compile: ${(decl as any).name.text}@${analysis.decoratorName} (resolved: ${ logs.push(`compile: ${(decl as any).name.text}@${analysis.decoratorName} (resolved: ${
analysis.resolved})`); analysis.resolved})`);
return `@${analysis.decoratorName} (compiled)`; return `@${analysis.decoratorName} (compiled)`;
@ -414,7 +414,7 @@ runInEachFileSystem(() => {
expect(testHandler.analyze).toHaveBeenCalled(); expect(testHandler.analyze).toHaveBeenCalled();
expect(testHandler.register).not.toHaveBeenCalled(); expect(testHandler.register).not.toHaveBeenCalled();
expect(testHandler.resolve).not.toHaveBeenCalled(); expect(testHandler.resolve).not.toHaveBeenCalled();
expect(testHandler.compile).not.toHaveBeenCalled(); expect(testHandler.compileFull).not.toHaveBeenCalled();
}); });
it('should report resolve diagnostics to the `diagnosticHandler` callback', () => { it('should report resolve diagnostics to the `diagnosticHandler` callback', () => {
@ -436,7 +436,7 @@ runInEachFileSystem(() => {
expect(testHandler.analyze).toHaveBeenCalled(); expect(testHandler.analyze).toHaveBeenCalled();
expect(testHandler.register).toHaveBeenCalled(); expect(testHandler.register).toHaveBeenCalled();
expect(testHandler.resolve).toHaveBeenCalled(); expect(testHandler.resolve).toHaveBeenCalled();
expect(testHandler.compile).not.toHaveBeenCalled(); expect(testHandler.compileFull).not.toHaveBeenCalled();
}); });
}); });
@ -452,7 +452,7 @@ runInEachFileSystem(() => {
analyze(): AnalysisOutput<unknown> { analyze(): AnalysisOutput<unknown> {
throw new Error('analyze should not have been called'); throw new Error('analyze should not have been called');
} }
compile(): CompileResult { compileFull(): CompileResult {
throw new Error('compile should not have been called'); throw new Error('compile should not have been called');
} }
} }

View File

@ -209,7 +209,7 @@ class DetectDecoratorHandler implements DecoratorHandler<unknown, unknown, unkno
return {}; return {};
} }
compile(node: ClassDeclaration): CompileResult|CompileResult[] { compileFull(node: ClassDeclaration): CompileResult|CompileResult[] {
return []; return [];
} }
} }
@ -227,7 +227,7 @@ class DiagnosticProducingHandler implements DecoratorHandler<unknown, unknown, u
return {diagnostics: [makeDiagnostic(9999, node, 'test diagnostic')]}; return {diagnostics: [makeDiagnostic(9999, node, 'test diagnostic')]};
} }
compile(node: ClassDeclaration): CompileResult|CompileResult[] { compileFull(node: ClassDeclaration): CompileResult|CompileResult[] {
return []; return [];
} }
} }

View File

@ -309,7 +309,7 @@ class TestHandler implements DecoratorHandler<unknown, unknown, unknown> {
return {}; return {};
} }
compile(node: ClassDeclaration): CompileResult|CompileResult[] { compileFull(node: ClassDeclaration): CompileResult|CompileResult[] {
this.log.push(this.name + ':compile:' + node.name.text); this.log.push(this.name + ':compile:' + node.name.text);
return []; return [];
} }

View File

@ -585,7 +585,7 @@ export class ComponentDecoratorHandler implements
return {data}; return {data};
} }
compile( compileFull(
node: ClassDeclaration, analysis: Readonly<ComponentAnalysisData>, node: ClassDeclaration, analysis: Readonly<ComponentAnalysisData>,
resolution: Readonly<ComponentResolutionData>, pool: ConstantPool): CompileResult[] { resolution: Readonly<ComponentResolutionData>, pool: ConstantPool): CompileResult[] {
const meta: R3ComponentMetadata = {...analysis.meta, ...resolution}; const meta: R3ComponentMetadata = {...analysis.meta, ...resolution};

View File

@ -151,7 +151,7 @@ export class DirectiveDecoratorHandler implements
return {diagnostics: diagnostics.length > 0 ? diagnostics : undefined}; return {diagnostics: diagnostics.length > 0 ? diagnostics : undefined};
} }
compile( compileFull(
node: ClassDeclaration, analysis: Readonly<DirectiveHandlerData>, node: ClassDeclaration, analysis: Readonly<DirectiveHandlerData>,
resolution: Readonly<unknown>, pool: ConstantPool): CompileResult[] { resolution: Readonly<unknown>, pool: ConstantPool): CompileResult[] {
const meta = analysis.meta; const meta = analysis.meta;

View File

@ -87,7 +87,7 @@ export class InjectableDecoratorHandler implements
this.injectableRegistry.registerInjectable(node); this.injectableRegistry.registerInjectable(node);
} }
compile(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>): CompileResult[] { compileFull(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>): CompileResult[] {
const res = compileIvyInjectable(analysis.meta); const res = compileIvyInjectable(analysis.meta);
const statements = res.statements; const statements = res.statements;
const results: CompileResult[] = []; const results: CompileResult[] = [];

View File

@ -371,7 +371,7 @@ export class NgModuleDecoratorHandler implements
} }
} }
compile( compileFull(
node: ClassDeclaration, analysis: Readonly<NgModuleAnalysis>, node: ClassDeclaration, analysis: Readonly<NgModuleAnalysis>,
resolution: Readonly<NgModuleResolution>): CompileResult[] { resolution: Readonly<NgModuleResolution>): CompileResult[] {
// Merge the injector imports (which are 'exports' that were later found to be NgModules) // Merge the injector imports (which are 'exports' that were later found to be NgModules)

View File

@ -133,7 +133,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
return {}; return {};
} }
compile(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): CompileResult[] { compileFull(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): CompileResult[] {
const meta = analysis.meta; const meta = analysis.meta;
const res = compilePipeFromMetadata(meta); const res = compilePipeFromMetadata(meta);
const factoryRes = compileNgFactoryDefField({ const factoryRes = compileNgFactoryDefField({

View File

@ -22,7 +22,7 @@ runInEachFileSystem(() => {
const {handler, TestClass, ɵprov, analysis} = const {handler, TestClass, ɵprov, analysis} =
setupHandler(/* errorOnDuplicateProv */ true); setupHandler(/* errorOnDuplicateProv */ true);
try { try {
handler.compile(TestClass, analysis); handler.compileFull(TestClass, analysis);
return fail('Compilation should have failed'); return fail('Compilation should have failed');
} catch (err) { } catch (err) {
if (!(err instanceof FatalDiagnosticError)) { if (!(err instanceof FatalDiagnosticError)) {
@ -39,7 +39,7 @@ runInEachFileSystem(() => {
() => { () => {
const {handler, TestClass, ɵprov, analysis} = const {handler, TestClass, ɵprov, analysis} =
setupHandler(/* errorOnDuplicateProv */ false); setupHandler(/* errorOnDuplicateProv */ false);
const res = handler.compile(TestClass, analysis); const res = handler.compileFull(TestClass, analysis);
expect(res).not.toContain(jasmine.objectContaining({name: 'ɵprov'})); expect(res).not.toContain(jasmine.objectContaining({name: 'ɵprov'}));
}); });
}); });

View File

@ -48,6 +48,22 @@ export interface TestOnlyOptions {
tracePerformance?: string; tracePerformance?: string;
} }
/**
* Options that specify compilation target.
*/
export interface TargetOptions {
/**
* Specifies the compilation mode to use. The following modes are available:
* - 'full': generates fully AOT compiled code using Ivy instructions.
* - 'partial': generates code in a stable, but intermediate form suitable to be published to NPM.
*
* To become public once the linker is ready.
*
* @internal
*/
compilationMode?: 'full'|'partial';
}
/** /**
* A merged interface of all of the various Angular compiler options, as well as the standard * A merged interface of all of the various Angular compiler options, as well as the standard
* `ts.CompilerOptions`. * `ts.CompilerOptions`.
@ -56,4 +72,5 @@ export interface TestOnlyOptions {
*/ */
export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options, export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options,
NgcCompatibilityOptions, StrictTemplateOptions, NgcCompatibilityOptions, StrictTemplateOptions,
TestOnlyOptions, I18nOptions, MiscOptions {} TestOnlyOptions, I18nOptions, TargetOptions,
MiscOptions {}

View File

@ -27,7 +27,7 @@ import {entryPointKeyFor, NgModuleRouteAnalyzer} from '../../routing';
import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope'; import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
import {generatedFactoryTransform} from '../../shims'; import {generatedFactoryTransform} from '../../shims';
import {ivySwitchTransform} from '../../switch'; import {ivySwitchTransform} from '../../switch';
import {aliasTransformFactory, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform'; import {aliasTransformFactory, CompilationMode, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
import {TemplateTypeCheckerImpl} from '../../typecheck'; import {TemplateTypeCheckerImpl} from '../../typecheck';
import {OptimizeFor, TemplateTypeChecker, TypeCheckingConfig, TypeCheckingProgramStrategy} from '../../typecheck/api'; import {OptimizeFor, TemplateTypeChecker, TypeCheckingConfig, TypeCheckingProgramStrategy} from '../../typecheck/api';
import {isTemplateDiagnostic} from '../../typecheck/diagnostics'; import {isTemplateDiagnostic} from '../../typecheck/diagnostics';
@ -761,9 +761,11 @@ export class NgCompiler {
this.closureCompilerEnabled, injectableRegistry, this.options.i18nInLocale), this.closureCompilerEnabled, injectableRegistry, this.options.i18nInLocale),
]; ];
const compilationMode =
this.options.compilationMode === 'partial' ? CompilationMode.PARTIAL : CompilationMode.FULL;
const traitCompiler = new TraitCompiler( const traitCompiler = new TraitCompiler(
handlers, reflector, this.perfRecorder, this.incrementalDriver, handlers, reflector, this.perfRecorder, this.incrementalDriver,
this.options.compileNonExportedClasses !== false, dtsTransforms); this.options.compileNonExportedClasses !== false, compilationMode, dtsTransforms);
const templateTypeChecker = new TemplateTypeCheckerImpl( const templateTypeChecker = new TemplateTypeCheckerImpl(
this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler, this.tsProgram, this.typeCheckingProgramStrategy, traitCompiler,

View File

@ -15,6 +15,21 @@ import {ClassDeclaration, Decorator} from '../../reflection';
import {ImportManager} from '../../translator'; import {ImportManager} from '../../translator';
import {TypeCheckContext} from '../../typecheck/api'; import {TypeCheckContext} from '../../typecheck/api';
/**
* Specifies the compilation mode that is used for the compilation.
*/
export enum CompilationMode {
/**
* Generates fully AOT compiled code using Ivy instructions.
*/
FULL,
/**
* Generates code using a stable, but intermediate format suitable to be published to NPM.
*/
PARTIAL,
}
export enum HandlerPrecedence { export enum HandlerPrecedence {
/** /**
* Handler with PRIMARY precedence cannot overlap - there can only be one on a given class. * Handler with PRIMARY precedence cannot overlap - there can only be one on a given class.
@ -147,10 +162,25 @@ export interface DecoratorHandler<D, A, R> {
/** /**
* Generate a description of the field which should be added to the class, including any * Generate a description of the field which should be added to the class, including any
* initialization code to be generated. * initialization code to be generated.
*
* If the compilation mode is configured as partial, and an implementation of `compilePartial` is
* provided, then this method is not called.
*/ */
compile( compileFull(
node: ClassDeclaration, analysis: Readonly<A>, resolution: Readonly<R>, node: ClassDeclaration, analysis: Readonly<A>, resolution: Readonly<R>,
constantPool: ConstantPool): CompileResult|CompileResult[]; constantPool: ConstantPool): CompileResult|CompileResult[];
/**
* Generates code for the decorator using a stable, but intermediate format suitable to be
* published to NPM. This code is meant to be processed by the linker to achieve the final AOT
* compiled code.
*
* If present, this method is used if the compilation mode is configured as partial, otherwise
* `compileFull` is.
*/
compilePartial?
(node: ClassDeclaration, analysis: Readonly<A>, resolution: Readonly<R>): CompileResult
|CompileResult[];
} }
/** /**

View File

@ -17,7 +17,7 @@ import {ClassDeclaration, Decorator, ReflectionHost} from '../../reflection';
import {ProgramTypeCheckAdapter, TypeCheckContext} from '../../typecheck/api'; import {ProgramTypeCheckAdapter, TypeCheckContext} from '../../typecheck/api';
import {getSourceFile, isExported} from '../../util/src/typescript'; import {getSourceFile, isExported} from '../../util/src/typescript';
import {AnalysisOutput, CompileResult, DecoratorHandler, HandlerFlags, HandlerPrecedence, ResolveResult} from './api'; import {AnalysisOutput, CompilationMode, CompileResult, DecoratorHandler, HandlerFlags, HandlerPrecedence, ResolveResult} from './api';
import {DtsTransformRegistry} from './declaration'; import {DtsTransformRegistry} from './declaration';
import {PendingTrait, Trait, TraitState} from './trait'; import {PendingTrait, Trait, TraitState} from './trait';
@ -88,7 +88,8 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
private handlers: DecoratorHandler<unknown, unknown, unknown>[], private handlers: DecoratorHandler<unknown, unknown, unknown>[],
private reflector: ReflectionHost, private perf: PerfRecorder, private reflector: ReflectionHost, private perf: PerfRecorder,
private incrementalBuild: IncrementalBuild<ClassRecord, unknown>, private incrementalBuild: IncrementalBuild<ClassRecord, unknown>,
private compileNonExportedClasses: boolean, private dtsTransforms: DtsTransformRegistry) { private compileNonExportedClasses: boolean, private compilationMode: CompilationMode,
private dtsTransforms: DtsTransformRegistry) {
for (const handler of handlers) { for (const handler of handlers) {
this.handlersByName.set(handler.name, handler); this.handlersByName.set(handler.name, handler);
} }
@ -479,8 +480,17 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
} }
const compileSpan = this.perf.start('compileClass', original); const compileSpan = this.perf.start('compileClass', original);
const compileMatchRes =
trait.handler.compile(clazz, trait.analysis, trait.resolution, constantPool); let compileRes: CompileResult|CompileResult[];
if (this.compilationMode === CompilationMode.PARTIAL &&
trait.handler.compilePartial !== undefined) {
compileRes = trait.handler.compilePartial(clazz, trait.analysis, trait.resolution);
} else {
compileRes =
trait.handler.compileFull(clazz, trait.analysis, trait.resolution, constantPool);
}
const compileMatchRes = compileRes;
this.perf.stop(compileSpan); this.perf.stop(compileSpan);
if (Array.isArray(compileMatchRes)) { if (Array.isArray(compileMatchRes)) {
for (const result of compileMatchRes) { for (const result of compileMatchRes) {

View File

@ -5,13 +5,16 @@
* Use of this source code is governed by an MIT-style license that can be * Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ConstantPool} from '@angular/compiler';
import * as o from '@angular/compiler/src/output/output_ast';
import {absoluteFrom} from '../../file_system'; import {absoluteFrom} from '../../file_system';
import {runInEachFileSystem} from '../../file_system/testing'; import {runInEachFileSystem} from '../../file_system/testing';
import {NOOP_INCREMENTAL_BUILD} from '../../incremental'; import {NOOP_INCREMENTAL_BUILD} from '../../incremental';
import {NOOP_PERF_RECORDER} from '../../perf'; import {NOOP_PERF_RECORDER} from '../../perf';
import {TypeScriptReflectionHost} from '../../reflection'; import {ClassDeclaration, Decorator, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
import {makeProgram} from '../../testing'; import {getDeclaration, makeProgram} from '../../testing';
import {DtsTransformRegistry, TraitCompiler} from '../../transform'; import {CompilationMode, DetectResult, DtsTransformRegistry, TraitCompiler} from '../../transform';
import {AnalysisOutput, CompileResult, DecoratorHandler, HandlerPrecedence} from '../src/api'; import {AnalysisOutput, CompileResult, DecoratorHandler, HandlerPrecedence} from '../src/api';
runInEachFileSystem(() => { runInEachFileSystem(() => {
@ -30,7 +33,7 @@ runInEachFileSystem(() => {
analyze(): AnalysisOutput<unknown> { analyze(): AnalysisOutput<unknown> {
throw new Error('analyze should not have been called'); throw new Error('analyze should not have been called');
} }
compile(): CompileResult { compileFull(): CompileResult {
throw new Error('compile should not have been called'); throw new Error('compile should not have been called');
} }
} }
@ -43,12 +46,133 @@ runInEachFileSystem(() => {
const reflectionHost = new TypeScriptReflectionHost(checker); const reflectionHost = new TypeScriptReflectionHost(checker);
const compiler = new TraitCompiler( const compiler = new TraitCompiler(
[new FakeDecoratorHandler()], reflectionHost, NOOP_PERF_RECORDER, NOOP_INCREMENTAL_BUILD, [new FakeDecoratorHandler()], reflectionHost, NOOP_PERF_RECORDER, NOOP_INCREMENTAL_BUILD,
true, new DtsTransformRegistry()); true, CompilationMode.FULL, new DtsTransformRegistry());
const sourceFile = program.getSourceFile('lib.d.ts')!; const sourceFile = program.getSourceFile('lib.d.ts')!;
const analysis = compiler.analyzeSync(sourceFile); const analysis = compiler.analyzeSync(sourceFile);
expect(sourceFile.isDeclarationFile).toBe(true); expect(sourceFile.isDeclarationFile).toBe(true);
expect(analysis).toBeFalsy(); expect(analysis).toBeFalsy();
}); });
describe('compilation mode', () => {
class PartialDecoratorHandler implements DecoratorHandler<{}, {}, unknown> {
name = 'PartialDecoratorHandler';
precedence = HandlerPrecedence.PRIMARY;
detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<{}>|undefined {
if (node.name.text !== 'Partial') {
return undefined;
}
return {trigger: node, decorator: null, metadata: {}};
}
analyze(): AnalysisOutput<unknown> {
return {analysis: {}};
}
compileFull(): CompileResult {
return {
name: 'compileFull',
initializer: o.literal(true),
statements: [],
type: o.BOOL_TYPE
};
}
compilePartial(): CompileResult {
return {
name: 'compilePartial',
initializer: o.literal(true),
statements: [],
type: o.BOOL_TYPE
};
}
}
class FullDecoratorHandler implements DecoratorHandler<{}, {}, unknown> {
name = 'FullDecoratorHandler';
precedence = HandlerPrecedence.PRIMARY;
detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<{}>|undefined {
if (node.name.text !== 'Full') {
return undefined;
}
return {trigger: node, decorator: null, metadata: {}};
}
analyze(): AnalysisOutput<unknown> {
return {analysis: {}};
}
compileFull(): CompileResult {
return {
name: 'compileFull',
initializer: o.literal(true),
statements: [],
type: o.BOOL_TYPE
};
}
}
it('should run partial compilation when implemented if compilation mode is partial', () => {
const {program} = makeProgram([{
name: _('/test.ts'),
contents: `
export class Full {}
export class Partial {}
`,
}]);
const checker = program.getTypeChecker();
const reflectionHost = new TypeScriptReflectionHost(checker);
const compiler = new TraitCompiler(
[new PartialDecoratorHandler(), new FullDecoratorHandler()], reflectionHost,
NOOP_PERF_RECORDER, NOOP_INCREMENTAL_BUILD, true, CompilationMode.PARTIAL,
new DtsTransformRegistry());
const sourceFile = program.getSourceFile('test.ts')!;
compiler.analyzeSync(sourceFile);
compiler.resolve();
const partialDecl =
getDeclaration(program, _('/test.ts'), 'Partial', isNamedClassDeclaration);
const partialResult = compiler.compile(partialDecl, new ConstantPool())!;
expect(partialResult.length).toBe(1);
expect(partialResult[0].name).toBe('compilePartial');
const fullDecl = getDeclaration(program, _('/test.ts'), 'Full', isNamedClassDeclaration);
const fullResult = compiler.compile(fullDecl, new ConstantPool())!;
expect(fullResult.length).toBe(1);
expect(fullResult[0].name).toBe('compileFull');
});
it('should run full compilation if compilation mode is full', () => {
const {program} = makeProgram([{
name: _('/test.ts'),
contents: `
export class Full {}
export class Partial {}
`,
}]);
const checker = program.getTypeChecker();
const reflectionHost = new TypeScriptReflectionHost(checker);
const compiler = new TraitCompiler(
[new PartialDecoratorHandler(), new FullDecoratorHandler()], reflectionHost,
NOOP_PERF_RECORDER, NOOP_INCREMENTAL_BUILD, true, CompilationMode.FULL,
new DtsTransformRegistry());
const sourceFile = program.getSourceFile('test.ts')!;
compiler.analyzeSync(sourceFile);
compiler.resolve();
const partialDecl =
getDeclaration(program, _('/test.ts'), 'Partial', isNamedClassDeclaration);
const partialResult = compiler.compile(partialDecl, new ConstantPool())!;
expect(partialResult.length).toBe(1);
expect(partialResult[0].name).toBe('compileFull');
const fullDecl = getDeclaration(program, _('/test.ts'), 'Full', isNamedClassDeclaration);
const fullResult = compiler.compile(fullDecl, new ConstantPool())!;
expect(fullResult.length).toBe(1);
expect(fullResult[0].name).toBe('compileFull');
});
});
}); });
}); });