Skip to content

Commit

Permalink
refactor: move signals code into primitives package
Browse files Browse the repository at this point in the history
This commit reorganizes the Angular code a bit, and moves signals into a
newly defined `@angular/core/primitives` location. This will be used inside
g3 to allow non-Angular targets to depend on the signals core without
incurring a dependency on the whole framework.
  • Loading branch information
alxhub committed Oct 4, 2023
1 parent 2520153 commit 5e1987f
Show file tree
Hide file tree
Showing 34 changed files with 173 additions and 27 deletions.
2 changes: 1 addition & 1 deletion docs/PUBLIC_API.md
Expand Up @@ -35,7 +35,7 @@ We explicitly don't consider the following to be our public API surface:
- any class members or symbols marked as `private`, or prefixed with underscore (`_`), [barred latin o](https://en.wikipedia.org/wiki/%C6%9F) (`ɵ`), and double barred latin o (`ɵɵ`).
- extending any of our classes unless the support for this is specifically documented in the API docs
- the contents and API surface of the code generated by Angular's compiler (with one notable exception: the existence and name of `NgModuleFactory` instances exported from generated code is guaranteed)

- the `@angular/core/primitives` package, including its child entrypoints

Our peer dependencies (such as TypeScript, Zone.js, or RxJS) are not considered part of our API surface, but they are included in our SemVer policies. We might update the required version of any of these dependencies in minor releases if the update doesn't cause breaking changes for Angular applications. Peer dependency updates that result in non-trivial breaking changes must be deferred to major Angular releases.

Expand Down
1 change: 1 addition & 0 deletions goldens/public-api/core/index.md
Expand Up @@ -5,6 +5,7 @@
```ts

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

Expand Down
140 changes: 140 additions & 0 deletions goldens/public-api/core/primitives/signals/index.md
@@ -0,0 +1,140 @@
## API Report File for "@angular/core_primitives_signals"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts

// @public
export function consumerAfterComputation(node: ReactiveNode | null, prevConsumer: ReactiveNode | null): void;

// @public
export function consumerBeforeComputation(node: ReactiveNode | null): ReactiveNode | null;

// @public
export function consumerDestroy(node: ReactiveNode): void;

// @public
export function createComputed<T>(computation: () => T): ComputedGetter<T>;

// @public
export function createSignal<T>(initialValue: T): SignalGetter<T>;

// @public (undocumented)
export function createWatch(fn: (onCleanup: WatchCleanupRegisterFn) => void, schedule: (watch: Watch) => void, allowSignalWrites: boolean): Watch;

// @public
export function defaultEquals<T>(a: T, b: T): boolean;

// @public (undocumented)
export function isInNotificationPhase(): boolean;

// @public (undocumented)
export function isReactive(value: unknown): value is Reactive;

// @public
export function producerAccessed(node: ReactiveNode): void;

// @public
export function producerNotifyConsumers(node: ReactiveNode): void;

// @public
export function producerUpdatesAllowed(): boolean;

// @public
export function producerUpdateValueVersion(node: ReactiveNode): void;

// @public (undocumented)
export interface Reactive {
// (undocumented)
[SIGNAL]: ReactiveNode;
}

// @public (undocumented)
export const REACTIVE_NODE: ReactiveNode;

// @public
export interface ReactiveNode {
consumerAllowSignalWrites: boolean;
// (undocumented)
readonly consumerIsAlwaysLive: boolean;
// (undocumented)
consumerMarkedDirty(node: unknown): void;
dirty: boolean;
liveConsumerIndexOfThis: number[] | undefined;
liveConsumerNode: ReactiveNode[] | undefined;
nextProducerIndex: number;
producerIndexOfThis: number[] | undefined;
producerLastReadVersion: Version[] | undefined;
producerMustRecompute(node: unknown): boolean;
producerNode: ReactiveNode[] | undefined;
// (undocumented)
producerRecomputeValue(node: unknown): void;
version: Version;
}

// @public (undocumented)
export function setActiveConsumer(consumer: ReactiveNode | null): ReactiveNode | null;

// @public (undocumented)
export function setAlternateWeakRefImpl(impl: unknown): void;

// @public (undocumented)
export function setPostSignalSetFn(fn: (() => void) | null): (() => void) | null;

// @public (undocumented)
export function setThrowInvalidWriteToSignalError(fn: () => never): void;

// @public
export const SIGNAL: unique symbol;

// @public (undocumented)
export type SignalGetter<T> = (() => T) & {
[SIGNAL]: SignalNode<T>;
};

// @public (undocumented)
export type SignalGetterOrNode<T> = SignalGetter<T> | SignalNode<T>;

// @public (undocumented)
export function signalMutateFn<T>(this: SignalGetterOrNode<T>, mutator: (value: T) => void): void;

// @public (undocumented)
export interface SignalNode<T> extends ReactiveNode {
// (undocumented)
[SIGNAL]: this;
// (undocumented)
equal: ValueEqualityFn<T>;
// (undocumented)
value: T;
}

// @public (undocumented)
export function signalSetFn<T>(this: SignalGetterOrNode<T>, newValue: T): void;

// @public (undocumented)
export function signalUpdateFn<T>(this: SignalGetterOrNode<T>, updater: (value: T) => T): void;

// @public
export type ValueEqualityFn<T> = (a: T, b: T) => boolean;

// @public (undocumented)
export interface Watch {
// (undocumented)
[SIGNAL]: WatchNode;
// (undocumented)
cleanup(): void;
destroy(): void;
// (undocumented)
notify(): void;
run(): void;
}

// @public
export type WatchCleanupFn = () => void;

// @public
export type WatchCleanupRegisterFn = (cleanupFn: WatchCleanupFn) => void;

// (No @packageDocumentation comment for this package)

```
1 change: 0 additions & 1 deletion packages.bzl
Expand Up @@ -63,7 +63,6 @@ DOCS_ENTRYPOINTS = [
"core/src/di/interface",
"core/src/interface",
"core/src/reflection",
"core/src/signals",
"core/src/util",
"core/testing",
"elements",
Expand Down
6 changes: 6 additions & 0 deletions packages/bazel/test/ng_package/core_package.spec.ts
Expand Up @@ -65,6 +65,12 @@ describe('@angular/core ng_package', () => {
esm: './esm2022/core.mjs',
default: './fesm2022/core.mjs'
},
'./primitives/signals': {
types: './primitives/signals/index.d.ts',
esm2022: './esm2022/primitives/signals/index.mjs',
esm: './esm2022/primitives/signals/index.mjs',
default: './fesm2022/primitives/signals.mjs',
},
'./rxjs-interop': {
types: './rxjs-interop/index.d.ts',
esm2022: './esm2022/rxjs-interop/rxjs-interop.mjs',
Expand Down
6 changes: 3 additions & 3 deletions packages/core/BUILD.bazel
Expand Up @@ -29,11 +29,11 @@ ng_module(
),
deps = [
"//packages:types",
"//packages/core/primitives/signals",
"//packages/core/src/compiler",
"//packages/core/src/di/interface",
"//packages/core/src/interface",
"//packages/core/src/reflection",
"//packages/core/src/signals",
"//packages/core/src/util",
"//packages/zone.js/lib:zone_d_ts",
"@npm//rxjs",
Expand Down Expand Up @@ -75,6 +75,7 @@ ng_package(
],
deps = [
":core",
"//packages/core/primitives/signals",
"//packages/core/rxjs-interop",
"//packages/core/testing",
],
Expand Down Expand Up @@ -102,7 +103,6 @@ api_golden_test(
"//packages/core/src/di/interface",
"//packages/core/src/interface",
"//packages/core/src/reflection",
"//packages/core/src/signals",
"//packages/core/src/util",
],
entry_point = "angular/packages/core/src/render3/global_utils_api.d.ts",
Expand All @@ -126,7 +126,7 @@ filegroup(
"src/**/*.ts",
]) + [
"PACKAGE.md",
"global/index.ts",
"global/PACKAGE.md",
"global/index.ts",
],
)
Expand Up @@ -14,9 +14,6 @@ ts_library(
"**/*.ts",
],
),
deps = [
"//packages/core/src/util",
],
)

tsec_test(
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -8,7 +8,7 @@

// Required as the signals library is in a separate package, so we need to explicitly ensure the
// global `ngDevMode` type is defined.
import '../../util/ng_dev_mode';
declare const ngDevMode: boolean|undefined;


/**
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion packages/core/rxjs-interop/test/BUILD.bazel
Expand Up @@ -15,7 +15,6 @@ ts_library(
"//packages:types",
"//packages/core",
"//packages/core/rxjs-interop",
"//packages/core/src/signals",
"//packages/core/testing",
"//packages/private/testing",
"@npm//rxjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/application_ref.ts
Expand Up @@ -8,6 +8,7 @@

import './util/ng_jit_mode';

import {setThrowInvalidWriteToSignalError} from '@angular/core/primitives/signals';
import {Observable, of, Subscription} from 'rxjs';
import {distinctUntilChanged, first, share, switchMap} from 'rxjs/operators';

Expand Down Expand Up @@ -42,7 +43,6 @@ import {setLocaleId} from './render3/i18n/i18n_locale_id';
import {setJitOptions} from './render3/jit/jit_options';
import {createNgModuleRefWithProviders, EnvironmentNgModuleRefAdapter, NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref';
import {publishDefaultGlobalUtils as _publishDefaultGlobalUtils} from './render3/util/global_utils';
import {setThrowInvalidWriteToSignalError} from './signals';
import {TESTABILITY} from './testability/testability';
import {isPromise} from './util/lang';
import {stringify} from './util/stringify';
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/core_private_export.ts
Expand Up @@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

export {setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl} from '../primitives/signals';
export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, internalCreateApplication as ɵinternalCreateApplication, whenStable as ɵwhenStable} from './application_ref';
export {ENABLED_SSR_FEATURES as ɵENABLED_SSR_FEATURES} from './application_tokens';
export {defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers} from './change_detection/change_detection';
Expand Down Expand Up @@ -33,7 +34,6 @@ export {DeferBlockBehavior as ɵDeferBlockBehavior, DeferBlockConfig as ɵDeferB
export {allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, BypassType as ɵBypassType, getSanitizationBypassType as ɵgetSanitizationBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass';
export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer';
export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer';
export {setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl} from './signals';
export {TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER} from './testability/testability';
export {booleanAttribute, numberAttribute} from './util/coercion';
export {devModeEqual as ɵdevModeEqual} from './util/comparison';
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/hooks.ts
Expand Up @@ -6,8 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/

import {setActiveConsumer} from '@angular/core/primitives/signals';

import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit} from '../interface/lifecycle_hooks';
import {setActiveConsumer} from '../signals';
import {assertDefined, assertEqual, assertNotEqual} from '../util/assert';

import {assertFirstCreatePass} from './assert';
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/instructions/shared.ts
Expand Up @@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import {consumerAfterComputation, consumerBeforeComputation, setActiveConsumer} from '@angular/core/primitives/signals';

import {Injector} from '../../di/injector';
import {ErrorHandler} from '../../error_handler';
import {RuntimeError, RuntimeErrorCode} from '../../errors';
Expand All @@ -18,7 +20,6 @@ import {Writable} from '../../interface/type';
import {SchemaMetadata} from '../../metadata/schema';
import {ViewEncapsulation} from '../../metadata/view';
import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization';
import {consumerAfterComputation, consumerBeforeComputation, setActiveConsumer} from '../../signals';
import {assertDefined, assertEqual, assertGreaterThan, assertGreaterThanOrEqual, assertIndexInRange, assertNotEqual, assertNotSame, assertSame, assertString} from '../../util/assert';
import {escapeCommentText} from '../../util/dom';
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/node_manipulation.ts
Expand Up @@ -6,10 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/

import {consumerDestroy} from '@angular/core/primitives/signals';

import {hasInSkipHydrationBlockFlag} from '../hydration/skip_hydration';
import {ViewEncapsulation} from '../metadata/view';
import {RendererStyleFlags2} from '../render/api_flags';
import {consumerDestroy} from '../signals';
import {addToArray, removeFromArray} from '../util/array_utils';
import {assertDefined, assertEqual, assertFunction, assertNumber, assertString} from '../util/assert';
import {escapeCommentText} from '../util/dom';
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/reactive_lview_consumer.ts
Expand Up @@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import {REACTIVE_NODE, ReactiveNode} from '../signals';
import {REACTIVE_NODE, ReactiveNode} from '@angular/core/primitives/signals';

import {assertDefined, assertEqual} from '../util/assert';

import {markViewDirty} from './instructions/mark_view_dirty';
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/reactivity/api.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {SIGNAL} from '../../signals';
import {SIGNAL} from '@angular/core/primitives/signals';

/**
* A reactive value which notifies consumers of any changes.
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/reactivity/computed.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {createComputed, SIGNAL} from '../../signals';
import {createComputed, SIGNAL} from '@angular/core/primitives/signals';

import {Signal, ValueEqualityFn} from './api';

Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/render3/reactivity/effect.ts
Expand Up @@ -6,14 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/

import {createWatch, Watch, WatchCleanupRegisterFn} from '@angular/core/primitives/signals';

import {assertInInjectionContext} from '../../di/contextual';
import {InjectionToken} from '../../di/injection_token';
import {Injector} from '../../di/injector';
import {inject} from '../../di/injector_compatibility';
import {ɵɵdefineInjectable} from '../../di/interface/defs';
import {ErrorHandler} from '../../error_handler';
import {DestroyRef} from '../../linker/destroy_ref';
import {createWatch, Watch, WatchCleanupRegisterFn} from '../../signals';


/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/reactivity/signal.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {createSignal, SIGNAL, SignalGetter, signalMutateFn, SignalNode, signalSetFn, signalUpdateFn} from '../../signals';
import {createSignal, SIGNAL, SignalGetter, signalMutateFn, SignalNode, signalSetFn, signalUpdateFn} from '@angular/core/primitives/signals';

import {Signal, ValueEqualityFn} from './api';

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/reactivity/untracked.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {setActiveConsumer} from '../../signals';
import {setActiveConsumer} from '@angular/core/primitives/signals';

/**
* Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function
Expand Down
1 change: 0 additions & 1 deletion packages/core/test/acceptance/BUILD.bazel
Expand Up @@ -23,7 +23,6 @@ ts_library(
"//packages/common/locales",
"//packages/compiler",
"//packages/core",
"//packages/core/src/signals",
"//packages/core/src/util",
"//packages/core/test/render3:matchers",
"//packages/core/testing",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/signals/BUILD.bazel
Expand Up @@ -10,7 +10,7 @@ ts_library(
),
deps = [
"//packages/core",
"//packages/core/src/signals",
"//packages/core/primitives/signals",
"//packages/core/src/util",
],
)
Expand Down

0 comments on commit 5e1987f

Please sign in to comment.