diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel index 0f84c449ae..bf5f2fa08b 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel @@ -10,10 +10,12 @@ ts_library( ]), deps = [ "//packages:types", + "//packages/compiler", "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/path", "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/testing", + "//packages/compiler-cli/src/ngtsc/translator", "//packages/compiler-cli/src/ngtsc/typecheck", "//packages/compiler-cli/src/ngtsc/util", "@npm//typescript", diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts new file mode 100644 index 0000000000..170c532f71 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * 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 + */ + +import {Expression, ExternalExpr, R3TargetBinder, SelectorMatcher, parseTemplate} from '@angular/compiler'; +import * as ts from 'typescript'; + +import {ImportMode, Reference, ReferenceEmitStrategy, ReferenceEmitter} from '../../imports'; +import {ClassDeclaration, isNamedClassDeclaration} from '../../reflection'; +import {ImportManager} from '../../translator'; +import {TypeCheckBlockMetadata} from '../src/api'; +import {generateTypeCheckBlock} from '../src/type_check_block'; + + +describe('type check blocks', () => { + it('should generate a basic block for a binding', + () => { expect(tcb('{{hello}}')).toContain('ctx.hello;'); }); +}); + +function getClass(sf: ts.SourceFile, name: string): ClassDeclaration { + for (const stmt of sf.statements) { + if (isNamedClassDeclaration(stmt) && stmt.name.text === name) { + return stmt; + } + } + throw new Error(`Class ${name} not found in file`); +} + + +function tcb(template: string): string { + const sf = ts.createSourceFile('synthetic.ts', 'class Test {}', ts.ScriptTarget.Latest, true); + + const clazz = getClass(sf, 'Test'); + const {nodes} = parseTemplate(template, 'synthetic.html'); + const matcher = new SelectorMatcher(); + const binder = new R3TargetBinder(matcher); + const boundTarget = binder.bind({template: nodes}); + + const meta: TypeCheckBlockMetadata = { + boundTarget, + fnName: 'Test_TCB', + }; + + const im = new ImportManager(undefined, 'i'); + const tcb = + generateTypeCheckBlock(clazz, meta, im, new ReferenceEmitter([new FakeReferenceStrategy()])); + + const res = ts.createPrinter().printNode(ts.EmitHint.Unspecified, tcb, sf); + return res.replace(/\s+/g, ' '); +} + +class FakeReferenceStrategy implements ReferenceEmitStrategy { + emit(ref: Reference, context: ts.SourceFile, importMode?: ImportMode): Expression { + return new ExternalExpr({ + moduleName: `types/${ref.debugName}`, + name: ref.debugName, + }); + } +}