Skip to content

Commit

Permalink
build: reuse fake core in type checking tests (#54344) (#54398)
Browse files Browse the repository at this point in the history
Currently we have two fake copies of `@angular/core` in the compiler tests which can be out of sync and cause inconsistent tests. These changes reuse a single copy instead.

PR Close #54344

PR Close #54398
  • Loading branch information
crisbeto authored and AndrewKushnir committed Feb 12, 2024
1 parent 6d00115 commit 277540c
Show file tree
Hide file tree
Showing 15 changed files with 63 additions and 141 deletions.
18 changes: 15 additions & 3 deletions packages/compiler-cli/src/ngtsc/testing/fake_core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ export interface WritableSignal<T> extends Signal<T> {
asReadonly(): Signal<T>;
}

// Note: needs to be kept in sync with the copies in `render3/reactivity/signal.ts` and
// `ngtsc/typecheck/testing/index.ts` to ensure consistent tests.
// Note: needs to be kept in sync with the copies in `render3/reactivity/signal.ts`.
export function ɵunwrapWritableSignal<T>(value: T|{[WRITABLE_SIGNAL]: T}): T {
return null!;
}
Expand Down Expand Up @@ -217,7 +216,20 @@ export const viewChildren: any = null!;
export const contentChild: any = null!;
export const contentChildren: any = null!;

export interface OutputEmitter<T> {
emit(value: T): void;
subscribe(listener: (v: T) => void): void;
}

/** Initializer-based output() API. */
export function output<T>(_opts?: {alias?: string}): EventEmitter<T> {
export function output<T>(_opts?: {alias?: string}): OutputEmitter<T> {
return null!;
}

export interface CreateComputedOptions<T> {
equal?: (a: T, b: T) => boolean;
}

export function computed<T>(computation: () => T, options?: CreateComputedOptions<T>): Signal<T> {
return null!;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
3 changes: 3 additions & 0 deletions packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ ts_library(
jasmine_node_test(
name = "test",
bootstrap = ["//tools/testing:node_no_angular"],
data = [
"//packages/compiler-cli/src/ngtsc/testing/fake_core:npm_package",
],
deps = [
":test_lib",
],
Expand Down
133 changes: 7 additions & 126 deletions packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/

import {BindingPipe, CssSelector, ParseSourceFile, ParseSourceSpan, parseTemplate, ParseTemplateOptions, R3TargetBinder, SchemaMetadata, SelectorMatcher, TmplAstElement} from '@angular/compiler';
import {readFileSync} from 'fs';
import path from 'path';
import ts from 'typescript';

import {absoluteFrom, AbsoluteFsPath, getSourceFileOrError, LogicalFileSystem} from '../../file_system';
Expand All @@ -18,7 +20,7 @@ import {NOOP_PERF_RECORDER} from '../../perf';
import {TsCreateProgramDriver} from '../../program_driver';
import {ClassDeclaration, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection';
import {ComponentScopeKind, ComponentScopeReader, LocalModuleScope, ScopeData, TypeCheckScopeRegistry} from '../../scope';
import {makeProgram} from '../../testing';
import {makeProgram, resolveFromRunfiles} from '../../testing';
import {getRootDirs} from '../../util/src/typescript';
import {OptimizeFor, ProgramTypeCheckAdapter, TemplateDiagnostic, TemplateTypeChecker, TypeCheckContext} from '../api';
import {TemplateId, TemplateSourceMapping, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata, TypeCheckingConfig} from '../api/api';
Expand Down Expand Up @@ -90,133 +92,12 @@ export function typescriptLibDts(): TestFile {
}

export function angularCoreDts(): TestFile {
const directory =
resolveFromRunfiles('angular/packages/compiler-cli/src/ngtsc/testing/fake_core/npm_package');

return {
name: absoluteFrom('/node_modules/@angular/core/index.d.ts'),
contents: `
export declare class TemplateRef<C> {
readonly elementRef: unknown;
createEmbeddedView(context: C): unknown;
}
export declare class EventEmitter<T> {
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): unknown;
subscribe(observerOrNext?: any, error?: any, complete?: any): unknown;
}
export declare type NgIterable<T> = Array<T> | Iterable<T>;
/**
* -------
* Signals
* ------
*/
export declare const SIGNAL: unique symbol;
export declare type Signal<T> = (() => T) & {
[SIGNAL]: unknown;
};
export declare function signal<T>(initialValue: T): WritableSignal<T>;
export declare function computed<T>(computation: () => T): Signal<T>;
const WRITABLE_SIGNAL = /* @__PURE__ */ Symbol('WRITABLE_SIGNAL');
export interface WritableSignal<T> extends Signal<T> {
[WRITABLE_SIGNAL]: T;
set(value: T): void;
update(updateFn: (value: T) => T): void;
asReadonly(): Signal<T>;
}
/**
* -------
* Signal inputs
* ------
*/
export interface InputOptions<ReadT, WriteT> {
alias?: string;
transform?: (v: WriteT) => ReadT;
}
export type InputOptionsWithoutTransform<ReadT> =
InputOptions<ReadT, ReadT>&{transform?: undefined};
export type InputOptionsWithTransform<ReadT, WriteT> =
Required<Pick<InputOptions<ReadT, WriteT>, 'transform'>>&InputOptions<ReadT, WriteT>;
const ɵINPUT_SIGNAL_BRAND_READ_TYPE: unique symbol;
export const ɵINPUT_SIGNAL_BRAND_WRITE_TYPE: unique symbol;
export interface InputSignalWithTransform<ReadT, WriteT> extends Signal<ReadT> {
[ɵINPUT_SIGNAL_BRAND_READ_TYPE]: ReadT;
[ɵINPUT_SIGNAL_BRAND_WRITE_TYPE]: WriteT;
}
export interface InputSignal<ReadT> extends InputSignalWithTransform<ReadT, ReadT> {}
export function inputFunction<ReadT>(): InputSignal<ReadT|undefined>;
export function inputFunction<ReadT>(
initialValue: ReadT, opts?: InputOptionsWithoutTransform<ReadT>): InputSignal<ReadT>;
export function inputFunction<ReadT, WriteT>(
initialValue: ReadT,
opts: InputOptionsWithTransform<ReadT, WriteT>): InputSignalWithTransform<ReadT, WriteT>;
export function inputFunction<ReadT, WriteT>(
_initialValue?: ReadT,
_opts?: InputOptions<ReadT, WriteT>): InputSignalWithTransform<ReadT|undefined, WriteT> {
return null!;
}
export function inputRequiredFunction<ReadT>(opts?: InputOptionsWithoutTransform<ReadT>):
InputSignal<ReadT>;
export function inputRequiredFunction<ReadT, WriteT>(
opts: InputOptionsWithTransform<ReadT, WriteT>): InputSignalWithTransform<ReadT, WriteT>;
export function inputRequiredFunction<ReadT, WriteT>(_opts?: InputSignalWithTransform<ReadT, WriteT>):
InputSignalWithTransform<ReadT, WriteT> {
return null!;
}
export type InputFunction = typeof inputFunction&{required: typeof inputRequiredFunction};
export const input: InputFunction = (() => {
(inputFunction as any).required = inputRequiredFunction;
return inputFunction as InputFunction;
})();
export type Signal<T> = (() => T);
// Note: needs to be kept in sync with the copies in render3/reactivity/signal.ts and
// fake_core/index.ts to ensure consistent tests.
export function ɵunwrapWritableSignal<T>(value: T|{[WRITABLE_SIGNAL]: T}): T {
return null!;
}
export interface ModelOptions {
alias?: string;
}
export interface ModelSignal<T> extends WritableSignal<T> {
[ɵINPUT_SIGNAL_BRAND_READ_TYPE]: T;
[ɵINPUT_SIGNAL_BRAND_WRITE_TYPE]: T;
subscribe(callback: (value: T) => void): {unsubscribe: () => void};
}
export interface ModelFunction {
<T>(): ModelSignal<T|undefined>;
<T>(initialValue: T, opts?: ModelOptions): ModelSignal<T>;
required<T>(opts?: ModelOptions): ModelSignal<T>;
}
export const model: ModelFunction = null!;
export type ɵUnwrapInputSignalWriteType<Field> =
Field extends InputSignalWithTransform<unknown, infer WriteT>? WriteT : never;
export type ɵUnwrapDirectiveSignalInputs<Dir, Fields extends keyof Dir> = {
[P in Fields]: ɵUnwrapInputSignalWriteType<Dir[P]>
};
export interface OutputEmitter<T> {
emit(value: T): void;
subscribe(listener: (v: T) => void): void;
}
`
contents: readFileSync(path.join(directory, 'index.d.ts'), 'utf8'),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class TestDir {
a: import("@angular/core").EventEmitter<unknown>;
b: import("@angular/core").EventEmitter<string>;
c: import("@angular/core").EventEmitter<void>;
a: import("@angular/core").OutputEmitter<unknown>;
b: import("@angular/core").OutputEmitter<string>;
c: import("@angular/core").OutputEmitter<void>;
static ɵfac: i0.ɵɵFactoryDeclaration<TestDir, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<TestDir, never, never, {}, { "a": "a"; "b": "b"; "c": "cPublic"; }, never, never, true, never>;
}
Expand Down Expand Up @@ -58,9 +58,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class TestComp {
a: import("@angular/core").EventEmitter<unknown>;
b: import("@angular/core").EventEmitter<string>;
c: import("@angular/core").EventEmitter<void>;
a: import("@angular/core").OutputEmitter<unknown>;
b: import("@angular/core").OutputEmitter<string>;
c: import("@angular/core").OutputEmitter<void>;
static ɵfac: i0.ɵɵFactoryDeclaration<TestComp, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<TestComp, "ng-component", never, {}, { "a": "a"; "b": "b"; "c": "cPublic"; }, never, never, true, never>;
}
Expand Down Expand Up @@ -102,9 +102,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDE
import { EventEmitter } from '@angular/core';
import * as i0 from "@angular/core";
export declare class TestDir {
click1: EventEmitter<unknown>;
click2: EventEmitter<boolean>;
_bla: EventEmitter<void>;
click1: import("@angular/core").OutputEmitter<unknown>;
click2: import("@angular/core").OutputEmitter<boolean>;
_bla: import("@angular/core").OutputEmitter<void>;
clickDecorator1: EventEmitter<unknown>;
clickDecorator2: EventEmitter<boolean>;
_blaDecorator: EventEmitter<void>;
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/render3/reactivity/signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ export interface WritableSignal<T> extends Signal<T> {
* @codeGenApi
*/
export function ɵunwrapWritableSignal<T>(value: T|{[WRITABLE_SIGNAL]: T}): T {
// Note: needs to be kept in sync with the copies in `fake_core/index.ts` and
// `ngtsc/typecheck/testing/index.ts` to ensure consistent tests.
// Note: needs to be kept in sync with the copy in `fake_core/index.ts`.
// Note: the function uses `WRITABLE_SIGNAL` as a brand instead of `WritableSignal<T>`,
// because the latter incorrectly unwraps non-signal getter functions.
return null!;
Expand Down
2 changes: 1 addition & 1 deletion packages/language-service/test/type_definitions_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('type definitions', () => {
project, {templateOverride: `<my-dir (name¦Changes)="doSmth()" />`});
expect(definitions!.length).toEqual(1);

assertTextSpans(definitions, ['EventEmitter']);
assertTextSpans(definitions, ['OutputEmitter']);
assertFileNames(definitions, ['index.d.ts']);
});
});
Expand Down

0 comments on commit 277540c

Please sign in to comment.