Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2 Signal inputs #53571

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
554283b
test(compiler-cli): additional type-check transform tests for signal …
devversion Nov 23, 2023
760b3a8
fix(core): `SignalNode` reactive node incorrectly exposing unset field
devversion Dec 7, 2023
6fe528c
refactor(core): expose `SIGNAL_NODE` to allow for advanced extensions…
devversion Dec 7, 2023
1c2ed8f
refactor(core): introduce runtime `InputSignal` implementation
devversion Nov 23, 2023
3688067
fixup! refactor(core): introduce runtime `InputSignal` implementation
devversion Dec 15, 2023
d1582a1
fixup! refactor(core): introduce runtime `InputSignal` implementation
devversion Dec 15, 2023
f9ba7b3
fixup! refactor(core): introduce runtime `InputSignal` implementation
devversion Dec 15, 2023
9615e55
refactor(core): initial test code for `setInput` to work with input s…
devversion Nov 23, 2023
c508dce
fix(core): do not accidentally inherit input transforms when overridden
devversion Dec 19, 2023
436bdd6
refactor(core): detect signal inputs at runtime using input flags
devversion Nov 28, 2023
54d199a
fixup! refactor(core): detect signal inputs at runtime using input flags
devversion Dec 15, 2023
e004b84
fixup! refactor(core): detect signal inputs at runtime using input flags
devversion Dec 15, 2023
7acc489
fixup! refactor(core): detect signal inputs at runtime using input flags
devversion Dec 15, 2023
ae71e8d
fixup! refactor(core): detect signal inputs at runtime using input flags
devversion Jan 3, 2024
3409b6e
refactor(core): type `EMPTY_OBJ` as `never` for improved type safety
devversion Nov 28, 2023
0e22688
test(core): add type signature test for signal input API
devversion Nov 30, 2023
16d4843
test(compiler-cli): add ngtsc test for new signal input API
devversion Dec 1, 2023
35b1795
fixup! test(compiler-cli): add ngtsc test for new signal input API
devversion Dec 15, 2023
043ec13
test: fix linker compliance tests after not running for a while
devversion Dec 4, 2023
4594fac
fixup! test: fix linker compliance tests after not running for a while
devversion Dec 17, 2023
c725ef7
build: re-enable linker compliance tests
devversion Dec 1, 2023
ca1d01d
refactor(compiler-cli): reference `InputFlags` enum directly for full…
devversion Dec 4, 2023
5c32349
fixup! refactor(compiler-cli): reference `InputFlags` enum directly f…
devversion Dec 16, 2023
1cc5515
fixup! refactor(compiler-cli): reference `InputFlags` enum directly f…
devversion Jan 3, 2024
d3b44e5
fixup! test(core): add type signature test for signal input API
devversion Dec 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions goldens/public-api/core/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { Observable } from 'rxjs';
import { SIGNAL } from '@angular/core/primitives/signals';
import { SignalNode } from '@angular/core/primitives/signals';
import { Subject } from 'rxjs';
import { Subscription } from 'rxjs';

Expand Down Expand Up @@ -874,10 +875,14 @@ export interface InputDecorator {
}

// @public
export type InputSignal<ReadT, WriteT = ReadT> = Signal<ReadT> & {
export interface InputSignal<ReadT, WriteT = ReadT> extends Signal<ReadT> {
// (undocumented)
[ɵINPUT_SIGNAL_BRAND_READ_TYPE]: ReadT;
// (undocumented)
[ɵINPUT_SIGNAL_BRAND_WRITE_TYPE]: WriteT;
};
// (undocumented)
[SIGNAL]: InputSignalNode<ReadT, WriteT>;
}

// @public
export function isDevMode(): boolean;
Expand Down
5 changes: 3 additions & 2 deletions goldens/public-api/core/primitives/signals/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ export function setThrowInvalidWriteToSignalError(fn: () => never): void;
// @public
export const SIGNAL: unique symbol;

// @public (undocumented)
export const SIGNAL_NODE: SignalNode<unknown>;

// @public (undocumented)
export interface SignalGetter<T> extends SignalBaseGetter<T> {
// (undocumented)
Expand All @@ -106,8 +109,6 @@ export function signalMutateFn<T>(node: SignalNode<T>, mutator: (value: T) => vo

// @public (undocumented)
export interface SignalNode<T> extends ReactiveNode {
// (undocumented)
readonly [SIGNAL]: SignalNode<T>;
// (undocumented)
equal: ValueEqualityFn<T>;
// (undocumented)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,79 @@ runInEachFileSystem(() => {
`TestComponent.html(3, 63): Type 'number' is not assignable to type 'null'.`,
],
},
// differing Write and ReadT
{
id: 'differing WriteT and ReadT, superset union, valid binding',
inputs: {
bla: {
type: 'InputSignal<boolean, boolean|string>',
isSignal: true,
},
},
template: `<div dir bla="string value">`,
expected: [],
},
{
id: 'differing WriteT and ReadT, superset union, invalid binding',
inputs: {
bla: {
type: 'InputSignal<boolean, boolean|string>',
isSignal: true,
},
},
template: `<div dir [bla]="2">`,
expected: [
`TestComponent.html(1, 11): Type '2' is not assignable to type 'string | boolean'.`,
],
},
{
id: 'differing WriteT and ReadT, divergent, valid binding',
inputs: {
bla: {
type: 'InputSignal<boolean, string>',
isSignal: true,
},
},
template: `<div dir bla="works">`,
expected: [],
},
{
id: 'differing WriteT and ReadT, divergent, invalid binding',
inputs: {
bla: {
type: 'InputSignal<boolean, string>',
isSignal: true,
},
},
template: `<div dir [bla]="true">`,
expected: [
`TestComponent.html(1, 11): Type 'boolean' is not assignable to type 'string'.`,
],
},
{
id: 'differing WriteT and ReadT, generic ctor inference',
inputs: {
bla: {
type: 'InputSignal<string, T>',
isSignal: true,
},
},
extraDirectiveMembers: [
`tester: {t: T, blaValue: never} = null!`,
],
directiveGenerics: '<T>',
template: `
<div dir [bla]="prop" #ref="dir"
(click)="ref.tester = {t: 0, blaValue: ref.bla()}">`,
component: `prop: HTMLElement = null!`,
expected: [
// This verifies that the `ref.tester.t` is correctly inferred to be `HTMLElement`.
`TestComponent.html(3, 46): Type 'number' is not assignable to type 'HTMLElement'.`,
// This verifies that the `bla` input value is still a `string` when accessed.
`TestComponent.html(3, 59): Type 'string' is not assignable to type 'never'.`,
],
},
// TODO(devversion): inline constructor test
];

for (const c of bindingCases) {
Expand Down
4 changes: 0 additions & 4 deletions packages/compiler-cli/test/compliance/linked/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ jasmine_node_test(
"//packages/compiler-cli/test/compliance/test_cases",
],
shard_count = 2,
tags = [
# TODO: renable this test after debugging the issues related to babel updates
"manual",
],
deps = [
":test_lib",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import {ComplianceTest} from '../test_helpers/get_compliance_tests';
import {parseGoldenPartial} from '../test_helpers/golden_partials';
import {runTests} from '../test_helpers/test_runner';

runTests('linked compile', linkPartials);
runTests('linked compile', linkPartials, {
// TODO: Remove when https://github.com/angular/angular/issues/51647 is resolved.
skipMappingChecks: true,
});

/**
* Link all the partials specified in the given `test`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
LifecycleComp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
type: LifecycleComp,
selectors: [["lifecycle-comp"]],
inputs: {nameMin: ["name", "nameMin"]},
inputs: {nameMin: [$r3$.ɵɵInputFlags.None, "name", "nameMin"]},
devversion marked this conversation as resolved.
Show resolved Hide resolved
features: [$r3$.ɵɵNgOnChangesFeature],
decls: 0,
vars: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ FooModule.ɵinj = /*@__PURE__*/ $i0$.ɵɵdefineInjector({});
(typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FooModule, [{
type: NgModule,
args: [{ declarations: [FooComponent, BarDirective, QuxPipe], bootstrap: [FooComponent] }]
}], null, null)
}], null, null);
})();
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ export function provideModule() {
return { ngModule: ForwardModule };
}
class TestModule {}
export class TestModule {}
TestModule.ɵfac = function TestModule_Factory(t) { return new (t || TestModule)(); };
TestModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: TestModule, imports: function () { return [ForwardModule]; } });
TestModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: TestModule, imports: () => [ForwardModule] });
TestModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [provideModule()] });
export { TestModule };
class ForwardModule {}
export class ForwardModule {}
ForwardModule.ɵfac = function ForwardModule_Factory(t) { return new (t || ForwardModule)(); };
ForwardModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: ForwardModule });
ForwardModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({});
export { ForwardModule };
ForwardModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({});
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
class AModule {}
export class AModule {}
AModule.ɵfac = function AModule_Factory(t) { return new (t || AModule)(); };
AModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: AModule, declarations: [A1Component, A2Component], exports: [A1Component, A2Component] });
AModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({});
export { AModule };
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AModule, [{
Expand All @@ -11,12 +10,10 @@ export { AModule };
}], null, null);
})();

class BModule {}
export class BModule {}
BModule.ɵfac = function BModule_Factory(t) { return new (t || BModule)(); };
BModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: BModule, declarations: [B1Component, B2Component], exports: [AModule] });
BModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [AModule] });
export { BModule };
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(BModule, [{
Expand All @@ -25,12 +22,10 @@ export { BModule };
}], null, null);
})();

class AppModule {}
export class AppModule {}
AppModule.ɵfac = function AppModule_Factory(t) { return new (t || AppModule)(); };
AppModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: AppModule, imports: [BModule] });
AppModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [BModule] });
export { AppModule };
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AppModule, [{
Expand Down