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:
parent
eec9f4a84e
commit
9d04b95166
|
@ -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[] {
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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[] = [];
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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'}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue