Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@angular/core

Package Overview
Dependencies
Maintainers
2
Versions
1053
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@angular/core - npm Package Compare versions

Comparing version
22.0.0-next.12
to
22.0.0-rc.0
+1007
schematics/bundles/index-DxFMpcXS.cjs
'use strict';
/**
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/
* License: MIT
*/
'use strict';
var ts = require('typescript');
var compilerCli = require('@angular/compiler-cli');
var migrations = require('@angular/compiler-cli/private/migrations');
require('node:path');
var project_paths = require('./project_paths-D2V-Uh2L.cjs');
var compiler = require('@angular/compiler');
function getMemberName(member) {
if (member.name === undefined) {
return null;
}
if (ts.isIdentifier(member.name) || ts.isStringLiteralLike(member.name)) {
return member.name.text;
}
if (ts.isPrivateIdentifier(member.name)) {
return `#${member.name.text}`;
}
return null;
}
/** Checks whether the given node can be an `@Input()` declaration node. */
function isInputContainerNode(node) {
return (((ts.isAccessor(node) && ts.isClassDeclaration(node.parent)) ||
ts.isPropertyDeclaration(node)) &&
getMemberName(node) !== null);
}
/**
* Detects `query(By.directive(T)).componentInstance` patterns and enhances
* them with information of `T`. This is important because `.componentInstance`
* is currently typed as `any` and may cause runtime test failures after input
* migrations then.
*
* The reference resolution pass leverages information from this pattern
* recognizer.
*/
class DebugElementComponentInstance {
checker;
cache = new WeakMap();
constructor(checker) {
this.checker = checker;
}
detect(node) {
if (this.cache.has(node)) {
return this.cache.get(node);
}
if (!ts.isPropertyAccessExpression(node)) {
return null;
}
// Check for `<>.componentInstance`.
if (!ts.isIdentifier(node.name) || node.name.text !== 'componentInstance') {
return null;
}
// Check for `<>.query(..).<>`.
if (!ts.isCallExpression(node.expression) ||
!ts.isPropertyAccessExpression(node.expression.expression) ||
!ts.isIdentifier(node.expression.expression.name) ||
node.expression.expression.name.text !== 'query') {
return null;
}
const queryCall = node.expression;
if (queryCall.arguments.length !== 1) {
return null;
}
const queryArg = queryCall.arguments[0];
let typeExpr;
if (ts.isCallExpression(queryArg) &&
queryArg.arguments.length === 1 &&
ts.isIdentifier(queryArg.arguments[0])) {
// Detect references, like: `query(By.directive(T))`.
typeExpr = queryArg.arguments[0];
}
else if (ts.isIdentifier(queryArg)) {
// Detect references, like: `harness.query(T)`.
typeExpr = queryArg;
}
else {
return null;
}
const symbol = this.checker.getSymbolAtLocation(typeExpr);
if (symbol?.valueDeclaration === undefined ||
!ts.isClassDeclaration(symbol?.valueDeclaration)) {
// Cache this as we use the expensive type checker.
this.cache.set(node, null);
return null;
}
const type = this.checker.getTypeAtLocation(symbol.valueDeclaration);
this.cache.set(node, type);
return type;
}
}
/**
* Recognizes `Partial<T>` instances in Catalyst tests. Those type queries
* are likely used for typing property initialization values for the given class `T`
* and we have a few scenarios:
*
* 1. The API does not unwrap signal inputs. In which case, the values are likely no
* longer assignable to an `InputSignal`.
* 2. The API does unwrap signal inputs, in which case we need to unwrap the `Partial`
* because the values are raw initial values, like they were before.
*
* We can enable this heuristic when we detect Catalyst as we know it supports unwrapping.
*/
class PartialDirectiveTypeInCatalystTests {
checker;
knownFields;
constructor(checker, knownFields) {
this.checker = checker;
this.knownFields = knownFields;
}
detect(node) {
// Detect `Partial<...>`
if (!ts.isTypeReferenceNode(node) ||
!ts.isIdentifier(node.typeName) ||
node.typeName.text !== 'Partial') {
return null;
}
// Ignore if the source file doesn't reference Catalyst.
if (!node.getSourceFile().text.includes('angular2/testing/catalyst')) {
return null;
}
// Extract T of `Partial<T>`.
const cmpTypeArg = node.typeArguments?.[0];
if (!cmpTypeArg ||
!ts.isTypeReferenceNode(cmpTypeArg) ||
!ts.isIdentifier(cmpTypeArg.typeName)) {
return null;
}
const cmpType = cmpTypeArg.typeName;
const symbol = this.checker.getSymbolAtLocation(cmpType);
// Note: Technically the class might be derived of an input-containing class,
// but this is out of scope for now. We can expand if we see it's a common case.
if (symbol?.valueDeclaration === undefined ||
!ts.isClassDeclaration(symbol.valueDeclaration) ||
!this.knownFields.shouldTrackClassReference(symbol.valueDeclaration)) {
return null;
}
return { referenceNode: node, targetClass: symbol.valueDeclaration };
}
}
/**
* Attempts to look up the given property access chain using
* the type checker.
*
* Notably this is not as safe as using the type checker directly to
* retrieve symbols of a given identifier, but in some cases this is
* a necessary approach to compensate e.g. for a lack of TCB information
* when processing Angular templates.
*
* The path is a list of properties to be accessed sequentially on the
* given type.
*/
function lookupPropertyAccess(checker, type, path, options = {}) {
let symbol = null;
for (const propName of path) {
// Note: We support assuming `NonNullable` for the pathl This is necessary
// in some situations as otherwise the lookups would fail to resolve the target
// symbol just because of e.g. a ternary. This is used in the signal input migration
// for host bindings.
type = options.ignoreNullability ? type.getNonNullableType() : type;
const propSymbol = type.getProperty(propName);
if (propSymbol === undefined) {
return null;
}
symbol = propSymbol;
type = checker.getTypeOfSymbol(propSymbol);
}
if (symbol === null) {
return null;
}
return { symbol, type };
}
/**
* AST visitor that iterates through a template and finds all
* input references.
*
* This resolution is important to be able to migrate references to inputs
* that will be migrated to signal inputs.
*/
class TemplateReferenceVisitor extends compiler.TmplAstRecursiveVisitor {
result = [];
/**
* Whether we are currently descending into HTML AST nodes
* where all bound attributes are considered potentially narrowing.
*
* Keeps track of all referenced inputs in such attribute expressions.
*/
templateAttributeReferencedFields = null;
expressionVisitor;
seenKnownFieldsCount = new Map();
constructor(typeChecker, templateTypeChecker, componentClass, knownFields, fieldNamesToConsiderForReferenceLookup) {
super();
this.expressionVisitor = new TemplateExpressionReferenceVisitor(typeChecker, templateTypeChecker, componentClass, knownFields, fieldNamesToConsiderForReferenceLookup);
}
checkExpressionForReferencedFields(activeNode, expressionNode) {
const referencedFields = this.expressionVisitor.checkTemplateExpression(activeNode, expressionNode);
// Add all references to the overall visitor result.
this.result.push(...referencedFields);
// Count usages of seen input references. We'll use this to make decisions
// based on whether inputs are potentially narrowed or not.
for (const input of referencedFields) {
this.seenKnownFieldsCount.set(input.targetField.key, (this.seenKnownFieldsCount.get(input.targetField.key) ?? 0) + 1);
}
return referencedFields;
}
descendAndCheckForNarrowedSimilarReferences(potentiallyNarrowedInputs, descend) {
const inputs = potentiallyNarrowedInputs.map((i) => ({
ref: i,
key: i.targetField.key,
pastCount: this.seenKnownFieldsCount.get(i.targetField.key) ?? 0,
}));
descend();
for (const input of inputs) {
// Input was referenced inside a narrowable spot, and is used in child nodes.
// This is a sign for the input to be narrowed. Mark it as such.
if ((this.seenKnownFieldsCount.get(input.key) ?? 0) > input.pastCount) {
input.ref.isLikelyNarrowed = true;
}
}
}
visitTemplate(template) {
// Note: We assume all bound expressions for templates may be subject
// to TCB narrowing. This is relevant for now until we support narrowing
// of signal calls in templates.
// TODO: Remove with: https://github.com/angular/angular/pull/55456.
this.templateAttributeReferencedFields = [];
compiler.tmplAstVisitAll(this, template.attributes);
compiler.tmplAstVisitAll(this, template.templateAttrs);
// If we are dealing with a microsyntax template, do not check
// inputs and outputs as those are already passed to the children.
// Template attributes may contain relevant expressions though.
if (template.tagName === 'ng-template') {
compiler.tmplAstVisitAll(this, template.inputs);
compiler.tmplAstVisitAll(this, template.outputs);
}
const referencedInputs = this.templateAttributeReferencedFields;
this.templateAttributeReferencedFields = null;
this.descendAndCheckForNarrowedSimilarReferences(referencedInputs, () => {
compiler.tmplAstVisitAll(this, template.children);
compiler.tmplAstVisitAll(this, template.references);
compiler.tmplAstVisitAll(this, template.variables);
});
}
visitIfBlockBranch(block) {
if (block.expression) {
const referencedFields = this.checkExpressionForReferencedFields(block, block.expression);
this.descendAndCheckForNarrowedSimilarReferences(referencedFields, () => {
super.visitIfBlockBranch(block);
});
}
else {
super.visitIfBlockBranch(block);
}
}
visitForLoopBlock(block) {
this.checkExpressionForReferencedFields(block, block.expression);
if (block.trackBy !== null) {
this.checkExpressionForReferencedFields(block, block.trackBy);
}
super.visitForLoopBlock(block);
}
visitSwitchBlock(block) {
const referencedFields = this.checkExpressionForReferencedFields(block, block.expression);
this.descendAndCheckForNarrowedSimilarReferences(referencedFields, () => {
super.visitSwitchBlock(block);
});
}
visitSwitchBlockCase(block) {
if (block.expression) {
const referencedFields = this.checkExpressionForReferencedFields(block, block.expression);
this.descendAndCheckForNarrowedSimilarReferences(referencedFields, () => {
super.visitSwitchBlockCase(block);
});
}
else {
super.visitSwitchBlockCase(block);
}
}
visitDeferredBlock(deferred) {
if (deferred.triggers.when) {
this.checkExpressionForReferencedFields(deferred, deferred.triggers.when.value);
}
if (deferred.prefetchTriggers.when) {
this.checkExpressionForReferencedFields(deferred, deferred.prefetchTriggers.when.value);
}
super.visitDeferredBlock(deferred);
}
visitBoundText(text) {
this.checkExpressionForReferencedFields(text, text.value);
}
visitBoundEvent(attribute) {
this.checkExpressionForReferencedFields(attribute, attribute.handler);
}
visitBoundAttribute(attribute) {
const referencedFields = this.checkExpressionForReferencedFields(attribute, attribute.value);
// Attributes inside templates are potentially "narrowed" and hence we
// keep track of all referenced inputs to see if they actually are.
if (this.templateAttributeReferencedFields !== null) {
this.templateAttributeReferencedFields.push(...referencedFields);
}
}
visitLetDeclaration(decl) {
this.checkExpressionForReferencedFields(decl, decl.value);
}
}
/**
* Expression AST visitor that checks whether a given expression references
* a known `@Input()`.
*
* This resolution is important to be able to migrate references to inputs
* that will be migrated to signal inputs.
*/
class TemplateExpressionReferenceVisitor extends compiler.RecursiveAstVisitor {
typeChecker;
templateTypeChecker;
componentClass;
knownFields;
fieldNamesToConsiderForReferenceLookup;
activeTmplAstNode = null;
detectedInputReferences = [];
isInsideObjectShorthandExpression = false;
insideConditionalExpressionsWithReads = [];
constructor(typeChecker, templateTypeChecker, componentClass, knownFields, fieldNamesToConsiderForReferenceLookup) {
super();
this.typeChecker = typeChecker;
this.templateTypeChecker = templateTypeChecker;
this.componentClass = componentClass;
this.knownFields = knownFields;
this.fieldNamesToConsiderForReferenceLookup = fieldNamesToConsiderForReferenceLookup;
}
/** Checks the given AST expression. */
checkTemplateExpression(activeNode, expressionNode) {
this.detectedInputReferences = [];
this.activeTmplAstNode = activeNode;
expressionNode.visit(this, []);
return this.detectedInputReferences;
}
visit(ast, context) {
super.visit(ast, [...context, ast]);
}
// Keep track when we are inside an object shorthand expression. This is
// necessary as we need to expand the shorthand to invoke a potential new signal.
// E.g. `{bla}` may be transformed to `{bla: bla()}`.
visitLiteralMap(ast, context) {
for (const [idx, key] of ast.keys.entries()) {
this.isInsideObjectShorthandExpression =
key.kind === 'property' && !!key.isShorthandInitialized;
ast.values[idx].visit(this, context);
this.isInsideObjectShorthandExpression = false;
}
}
visitPropertyRead(ast, context) {
this._inspectPropertyAccess(ast, false, context);
super.visitPropertyRead(ast, context);
}
visitSafePropertyRead(ast, context) {
this._inspectPropertyAccess(ast, false, context);
super.visitPropertyRead(ast, context);
}
visitBinary(ast, context) {
if (ast.operation === '=' && ast.left instanceof compiler.PropertyRead) {
this._inspectPropertyAccess(ast.left, true, [...context, ast, ast.left]);
}
else {
super.visitBinary(ast, context);
}
}
visitConditional(ast, context) {
this.visit(ast.condition, context);
this.insideConditionalExpressionsWithReads.push(ast.condition);
this.visit(ast.trueExp, context);
this.visit(ast.falseExp, context);
this.insideConditionalExpressionsWithReads.pop();
}
/**
* Inspects the property access and attempts to resolve whether they access
* a known field. If so, the result is captured.
*/
_inspectPropertyAccess(ast, isAssignment, astPath) {
if (this.fieldNamesToConsiderForReferenceLookup !== null &&
!this.fieldNamesToConsiderForReferenceLookup.has(ast.name)) {
return;
}
const isWrite = !!(isAssignment ||
(this.activeTmplAstNode && isTwoWayBindingNode(this.activeTmplAstNode)));
this._checkAccessViaTemplateTypeCheckBlock(ast, isWrite, astPath) ||
this._checkAccessViaOwningComponentClassType(ast, isWrite, astPath);
}
/**
* Checks whether the node refers to an input using the TCB information.
* Type check block may not exist for e.g. test components, so this can return `null`.
*/
_checkAccessViaTemplateTypeCheckBlock(ast, isWrite, astPath) {
// There might be no template type checker. E.g. if we check host bindings.
if (this.templateTypeChecker === null) {
return false;
}
const symbol = this.templateTypeChecker.getSymbolOfNode(ast, this.componentClass);
if (symbol?.kind !== migrations.SymbolKind.Expression) {
return false;
}
const tsSymbol = this.templateTypeChecker.getTsSymbolOfSymbol(symbol);
if (tsSymbol === null) {
return false;
}
// Dangerous: Type checking symbol retrieval is a totally different `ts.Program`,
// than the one where we analyzed `knownInputs`.
// --> Find the input via its input id.
const targetInput = this.knownFields.attemptRetrieveDescriptorFromSymbol(tsSymbol);
if (targetInput === null) {
return false;
}
this.detectedInputReferences.push({
targetNode: targetInput.node,
targetField: targetInput,
read: ast,
readAstPath: astPath,
context: this.activeTmplAstNode,
isLikelyNarrowed: this._isPartOfNarrowingTernary(ast),
isObjectShorthandExpression: this.isInsideObjectShorthandExpression,
isWrite,
});
return true;
}
/**
* Simple resolution checking whether the given AST refers to a known input.
* This is a fallback for when there is no type checking information (e.g. in host bindings).
*
* It attempts to resolve references by traversing accesses of the "component class" type.
* e.g. `this.bla` is resolved via `CompType#bla` and further.
*/
_checkAccessViaOwningComponentClassType(ast, isWrite, astPath) {
// We might check host bindings, which can never point to template variables or local refs.
const expressionTemplateTarget = this.templateTypeChecker === null
? null
: this.templateTypeChecker.getExpressionTarget(ast, this.componentClass);
// Skip checking if:
// - the reference resolves to a template variable or local ref. No way to resolve without TCB.
// - the owning component does not have a name (should not happen technically).
if (expressionTemplateTarget !== null || this.componentClass.name === undefined) {
return;
}
const property = traverseReceiverAndLookupSymbol(ast, this.componentClass, this.typeChecker);
if (property === null) {
return;
}
const matchingTarget = this.knownFields.attemptRetrieveDescriptorFromSymbol(property);
if (matchingTarget === null) {
return;
}
this.detectedInputReferences.push({
targetNode: matchingTarget.node,
targetField: matchingTarget,
read: ast,
readAstPath: astPath,
context: this.activeTmplAstNode,
isLikelyNarrowed: this._isPartOfNarrowingTernary(ast),
isObjectShorthandExpression: this.isInsideObjectShorthandExpression,
isWrite,
});
}
_isPartOfNarrowingTernary(read) {
// Note: We do not safe check that the reads are fully matching 1:1. This is acceptable
// as worst case we just skip an input from being migrated. This is very unlikely too.
return this.insideConditionalExpressionsWithReads.some((r) => (r instanceof compiler.PropertyRead || r instanceof compiler.SafePropertyRead) && r.name === read.name);
}
}
/**
* Emulates an access to a given field using the TypeScript `ts.Type`
* of the given class. The resolved symbol of the access is returned.
*/
function traverseReceiverAndLookupSymbol(readOrWrite, componentClass, checker) {
const path = [readOrWrite.name];
let node = readOrWrite;
while (node.receiver instanceof compiler.PropertyRead) {
node = node.receiver;
path.unshift(node.name);
}
if (!(node.receiver instanceof compiler.ImplicitReceiver)) {
return null;
}
const classType = checker.getTypeAtLocation(componentClass.name);
return (lookupPropertyAccess(checker, classType, path, {
// Necessary to avoid breaking the resolution if there is
// some narrowing involved. E.g. `myClass ? myClass.input`.
ignoreNullability: true,
})?.symbol ?? null);
}
/** Whether the given node refers to a two-way binding AST node. */
function isTwoWayBindingNode(node) {
return ((node instanceof compiler.TmplAstBoundAttribute && node.type === compiler.BindingType.TwoWay) ||
(node instanceof compiler.TmplAstBoundEvent && node.type === compiler.ParsedEventType.TwoWay));
}
/** Possible types of references to known fields detected. */
exports.ReferenceKind = void 0;
(function (ReferenceKind) {
ReferenceKind[ReferenceKind["InTemplate"] = 0] = "InTemplate";
ReferenceKind[ReferenceKind["InHostBinding"] = 1] = "InHostBinding";
ReferenceKind[ReferenceKind["TsReference"] = 2] = "TsReference";
ReferenceKind[ReferenceKind["TsClassTypeReference"] = 3] = "TsClassTypeReference";
})(exports.ReferenceKind || (exports.ReferenceKind = {}));
/** Whether the given reference is a TypeScript reference. */
function isTsReference(ref) {
return ref.kind === exports.ReferenceKind.TsReference;
}
/** Whether the given reference is a template reference. */
function isTemplateReference(ref) {
return ref.kind === exports.ReferenceKind.InTemplate;
}
/** Whether the given reference is a host binding reference. */
function isHostBindingReference(ref) {
return ref.kind === exports.ReferenceKind.InHostBinding;
}
/**
* Whether the given reference is a TypeScript `ts.Type` reference
* to a class containing known fields.
*/
function isTsClassTypeReference(ref) {
return ref.kind === exports.ReferenceKind.TsClassTypeReference;
}
/**
* Checks host bindings of the given class and tracks all
* references to inputs within bindings.
*/
function identifyHostBindingReferences(node, programInfo, checker, reflector, result, knownFields, fieldNamesToConsiderForReferenceLookup) {
if (node.name === undefined) {
return;
}
const decorators = reflector.getDecoratorsOfDeclaration(node);
if (decorators === null) {
return;
}
const angularDecorators = migrations.getAngularDecorators(decorators, ['Directive', 'Component'],
/* isAngularCore */ false);
if (angularDecorators.length === 0) {
return;
}
// Assume only one Angular decorator per class.
const ngDecorator = angularDecorators[0];
if (ngDecorator.args?.length !== 1) {
return;
}
const metadataNode = migrations.unwrapExpression(ngDecorator.args[0]);
if (!ts.isObjectLiteralExpression(metadataNode)) {
return;
}
const metadata = migrations.reflectObjectLiteral(metadataNode);
if (!metadata.has('host')) {
return;
}
let hostField = migrations.unwrapExpression(metadata.get('host'));
// Special-case in case host bindings are shared via a variable.
// e.g. Material button shares host bindings as a constant in the same target.
if (ts.isIdentifier(hostField)) {
let symbol = checker.getSymbolAtLocation(hostField);
// Plain identifier references can point to alias symbols (e.g. imports).
if (symbol !== undefined && symbol.flags & ts.SymbolFlags.Alias) {
symbol = checker.getAliasedSymbol(symbol);
}
if (symbol !== undefined &&
symbol.valueDeclaration !== undefined &&
ts.isVariableDeclaration(symbol.valueDeclaration)) {
hostField = symbol?.valueDeclaration.initializer;
}
}
if (hostField === undefined || !ts.isObjectLiteralExpression(hostField)) {
return;
}
const hostMap = migrations.reflectObjectLiteral(hostField);
const expressionResult = [];
const expressionVisitor = new TemplateExpressionReferenceVisitor(checker, null, node, knownFields, fieldNamesToConsiderForReferenceLookup);
for (const [rawName, expression] of hostMap.entries()) {
if (!ts.isStringLiteralLike(expression)) {
continue;
}
const isEventBinding = rawName.startsWith('(');
const isPropertyBinding = rawName.startsWith('[');
// Only migrate property or event bindings.
if (!isPropertyBinding && !isEventBinding) {
continue;
}
const parser = compiler.makeBindingParser();
const sourceSpan = new compiler.ParseSourceSpan(
// Fake source span to keep parsing offsets zero-based.
// We then later combine these with the expression TS node offsets.
new compiler.ParseLocation({ content: '', url: '' }, 0, 0, 0), new compiler.ParseLocation({ content: '', url: '' }, 0, 0, 0));
const name = rawName.substring(1, rawName.length - 1);
let parsed = undefined;
if (isEventBinding) {
const result = [];
parser.parseEvent(name.substring(1, name.length - 1), expression.text, false, sourceSpan, sourceSpan, [], result, sourceSpan);
parsed = result[0].handler;
}
else {
const result = [];
parser.parsePropertyBinding(name, expression.text, true,
/* isTwoWayBinding */ false, sourceSpan, 0, sourceSpan, [], result, sourceSpan);
parsed = result[0].expression;
}
if (parsed != null) {
expressionResult.push(...expressionVisitor.checkTemplateExpression(expression, parsed));
}
}
for (const ref of expressionResult) {
result.references.push({
kind: exports.ReferenceKind.InHostBinding,
from: {
read: ref.read,
readAstPath: ref.readAstPath,
isObjectShorthandExpression: ref.isObjectShorthandExpression,
isWrite: ref.isWrite,
file: project_paths.projectFile(ref.context.getSourceFile(), programInfo),
hostPropertyNode: ref.context,
},
target: ref.targetField,
});
}
}
/**
* Attempts to extract the `TemplateDefinition` for the given
* class, if possible.
*
* The definition can then be used with the Angular compiler to
* load/parse the given template.
*/
function attemptExtractTemplateDefinition(node, checker, reflector, resourceLoader) {
const classDecorators = reflector.getDecoratorsOfDeclaration(node);
const evaluator = new migrations.PartialEvaluator(reflector, checker, null);
const ngDecorators = classDecorators !== null
? migrations.getAngularDecorators(classDecorators, ['Component'], /* isAngularCore */ false)
: [];
if (ngDecorators.length === 0 ||
ngDecorators[0].args === null ||
ngDecorators[0].args.length === 0 ||
!ts.isObjectLiteralExpression(ngDecorators[0].args[0])) {
return null;
}
const properties = migrations.reflectObjectLiteral(ngDecorators[0].args[0]);
const templateProp = properties.get('template');
const templateUrlProp = properties.get('templateUrl');
const containingFile = node.getSourceFile().fileName;
// inline template.
if (templateProp !== undefined) {
const templateStr = evaluator.evaluate(templateProp);
if (typeof templateStr === 'string') {
return {
isInline: true,
expression: templateProp,
preserveWhitespaces: false,
resolvedTemplateUrl: containingFile,
templateUrl: containingFile,
};
}
}
try {
// external template.
if (templateUrlProp !== undefined) {
const templateUrl = evaluator.evaluate(templateUrlProp);
if (typeof templateUrl === 'string') {
return {
isInline: false,
preserveWhitespaces: false,
templateUrlExpression: templateUrlProp,
templateUrl,
resolvedTemplateUrl: resourceLoader.resolve(templateUrl, containingFile),
};
}
}
}
catch (e) {
console.error(`Could not parse external template: ${e}`);
}
return null;
}
/**
* Checks whether the given class has an Angular template, and resolves
* all of the references to inputs.
*/
function identifyTemplateReferences(programInfo, node, reflector, checker, evaluator, templateTypeChecker, resourceLoader, options, result, knownFields, fieldNamesToConsiderForReferenceLookup) {
const template = templateTypeChecker.getTemplate(node, compilerCli.OptimizeFor.WholeProgram) ??
// If there is no template registered in the TCB or compiler, the template may
// be skipped due to an explicit `jit: true` setting. We try to detect this case
// and parse the template manually.
extractTemplateWithoutCompilerAnalysis(node, checker, reflector, resourceLoader, evaluator, options);
if (template !== null) {
const visitor = new TemplateReferenceVisitor(checker, templateTypeChecker, node, knownFields, fieldNamesToConsiderForReferenceLookup);
template.forEach((node) => node.visit(visitor));
for (const res of visitor.result) {
const templateFilePath = res.context.sourceSpan.start.file.url;
// Templates without an URL are non-mappable artifacts of e.g.
// string concatenated templates. See the `indirect` template
// source mapping concept in the compiler. We skip such references
// as those cannot be migrated, but print an error for now.
if (templateFilePath === '') {
// TODO: Incorporate a TODO potentially.
console.error(`Found reference to field ${res.targetField.key} that cannot be ` +
`migrated because the template cannot be parsed with source map information ` +
`(in file: ${node.getSourceFile().fileName}).`);
continue;
}
result.references.push({
kind: exports.ReferenceKind.InTemplate,
from: {
read: res.read,
readAstPath: res.readAstPath,
node: res.context,
isObjectShorthandExpression: res.isObjectShorthandExpression,
originatingTsFile: project_paths.projectFile(node.getSourceFile(), programInfo),
templateFile: project_paths.projectFile(compilerCli.absoluteFrom(templateFilePath), programInfo),
isLikelyPartOfNarrowing: res.isLikelyNarrowed,
isWrite: res.isWrite,
},
target: res.targetField,
});
}
}
}
/**
* Attempts to extract a `@Component` template from the given class,
* without relying on the `NgCompiler` program analysis.
*
* This is useful for JIT components using `jit: true` which were not
* processed by the Angular compiler, but may still have templates that
* contain references to inputs that we can resolve via the fallback
* reference resolutions (that does not use the type check block).
*/
function extractTemplateWithoutCompilerAnalysis(node, checker, reflector, resourceLoader, evaluator, options) {
if (node.name === undefined) {
return null;
}
const tmplDef = attemptExtractTemplateDefinition(node, checker, reflector, resourceLoader);
if (tmplDef === null) {
return null;
}
return migrations.extractTemplate(node, tmplDef, evaluator, null, resourceLoader, {
enableBlockSyntax: true,
enableLetSyntax: true,
usePoisonedData: true,
enableI18nLegacyMessageIdFormat: options.enableI18nLegacyMessageIdFormat !== false,
i18nNormalizeLineEndingsInICUs: options.i18nNormalizeLineEndingsInICUs === true,
enableSelectorless: false,
}, migrations.CompilationMode.FULL).nodes;
}
/** Gets the pattern and property name for a given binding element. */
function resolveBindingElement(node) {
const name = node.propertyName ?? node.name;
// If we are discovering a non-analyzable element in the path, abort.
if (!ts.isStringLiteralLike(name) && !ts.isIdentifier(name)) {
return null;
}
return {
pattern: node.parent,
propertyName: name.text,
};
}
/** Gets the declaration node of the given binding element. */
function getBindingElementDeclaration(node) {
while (true) {
if (ts.isBindingElement(node.parent.parent)) {
node = node.parent.parent;
}
else {
return node.parent.parent;
}
}
}
/**
* Expands the given reference to its containing expression, capturing
* the full context.
*
* E.g. `traverseAccess(ref<`bla`>)` may return `this.bla`
* or `traverseAccess(ref<`bla`>)` may return `this.someObj.a.b.c.bla`.
*
* This helper is useful as we will replace the full access with a temporary
* variable for narrowing. Replacing just the identifier is wrong.
*/
function traverseAccess(access) {
if (ts.isPropertyAccessExpression(access.parent) && access.parent.name === access) {
return access.parent;
}
else if (ts.isElementAccessExpression(access.parent) &&
access.parent.argumentExpression === access) {
return access.parent;
}
return access;
}
/**
* Unwraps the parent of the given node, if it's a
* parenthesized expression or `as` expression.
*/
function unwrapParent(node) {
if (ts.isParenthesizedExpression(node.parent)) {
return unwrapParent(node.parent);
}
else if (ts.isAsExpression(node.parent)) {
return unwrapParent(node.parent);
}
return node;
}
/**
* List of binary operators that indicate a write operation.
*
* Useful for figuring out whether an expression assigns to
* something or not.
*/
const writeBinaryOperators = [
ts.SyntaxKind.EqualsToken,
ts.SyntaxKind.BarBarEqualsToken,
ts.SyntaxKind.BarEqualsToken,
ts.SyntaxKind.AmpersandEqualsToken,
ts.SyntaxKind.AmpersandAmpersandEqualsToken,
ts.SyntaxKind.SlashEqualsToken,
ts.SyntaxKind.MinusEqualsToken,
ts.SyntaxKind.PlusEqualsToken,
ts.SyntaxKind.CaretEqualsToken,
ts.SyntaxKind.PercentEqualsToken,
ts.SyntaxKind.AsteriskEqualsToken,
ts.SyntaxKind.ExclamationEqualsToken,
];
/**
* Checks whether given TypeScript reference refers to an Angular input, and captures
* the reference if possible.
*
* @param fieldNamesToConsiderForReferenceLookup List of field names that should be
* respected when expensively looking up references to known fields.
* May be null if all identifiers should be inspected.
*/
function identifyPotentialTypeScriptReference(node, programInfo, checker, knownFields, result, fieldNamesToConsiderForReferenceLookup, advisors) {
// Skip all identifiers that never can point to a migrated field.
// TODO: Capture these assumptions and performance optimizations in the design doc.
if (fieldNamesToConsiderForReferenceLookup !== null &&
!fieldNamesToConsiderForReferenceLookup.has(node.text)) {
return;
}
let target = undefined;
try {
// Resolve binding elements to their declaration symbol.
// Commonly inputs are accessed via object expansion. e.g. `const {input} = this;`.
if (ts.isBindingElement(node.parent)) {
// Skip binding elements that are using spread.
if (node.parent.dotDotDotToken !== undefined) {
return;
}
const bindingInfo = resolveBindingElement(node.parent);
if (bindingInfo === null) {
// The declaration could not be resolved. Skip analyzing this.
return;
}
const bindingType = checker.getTypeAtLocation(bindingInfo.pattern);
const resolved = lookupPropertyAccess(checker, bindingType, [bindingInfo.propertyName]);
target = resolved?.symbol;
}
else {
target = checker.getSymbolAtLocation(node);
}
}
catch (e) {
console.error('Unexpected error while trying to resolve identifier reference:');
console.error(e);
// Gracefully skip analyzing. This can happen when e.g. a reference is named similar
// to an input, but is dependant on `.d.ts` that is not necessarily available (clutz dts).
return;
}
noTargetSymbolCheck: if (target === undefined) {
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
const propAccessSymbol = checker.getSymbolAtLocation(node.parent.expression);
if (propAccessSymbol !== undefined &&
propAccessSymbol.valueDeclaration !== undefined &&
ts.isVariableDeclaration(propAccessSymbol.valueDeclaration) &&
propAccessSymbol.valueDeclaration.initializer !== undefined) {
target = advisors.debugElComponentInstanceTracker
.detect(propAccessSymbol.valueDeclaration.initializer)
?.getProperty(node.text);
// We found a target in the fallback path. Break out.
if (target !== undefined) {
break noTargetSymbolCheck;
}
}
}
return;
}
let targetInput = knownFields.attemptRetrieveDescriptorFromSymbol(target);
if (targetInput === null) {
return;
}
const access = unwrapParent(traverseAccess(node));
const accessParent = access.parent;
const isWriteReference = ts.isBinaryExpression(accessParent) &&
accessParent.left === access &&
writeBinaryOperators.includes(accessParent.operatorToken.kind);
// track accesses from source files to known fields.
result.references.push({
kind: exports.ReferenceKind.TsReference,
from: {
node,
file: project_paths.projectFile(node.getSourceFile(), programInfo),
isWrite: isWriteReference,
isPartOfElementBinding: ts.isBindingElement(node.parent),
},
target: targetInput,
});
}
/**
* Phase where we iterate through all source file references and
* detect references to known fields (e.g. commonly inputs).
*
* This is useful, for example in the signal input migration whe
* references need to be migrated to unwrap signals, given that
* their target properties is no longer holding a raw value, but
* instead an `InputSignal`.
*
* This phase detects references in all types of locations:
* - TS source files
* - Angular templates (inline or external)
* - Host binding expressions.
*/
function createFindAllSourceFileReferencesVisitor(programInfo, checker, reflector, resourceLoader, evaluator, templateTypeChecker, knownFields, fieldNamesToConsiderForReferenceLookup, result) {
const debugElComponentInstanceTracker = new DebugElementComponentInstance(checker);
const partialDirectiveCatalystTracker = new PartialDirectiveTypeInCatalystTests(checker, knownFields);
const perfCounters = {
template: 0,
hostBindings: 0,
tsReferences: 0,
tsTypes: 0,
};
// Schematic NodeJS execution may not have `global.performance` defined.
const currentTimeInMs = () => typeof global.performance !== 'undefined' ? global.performance.now() : Date.now();
const visitor = (node) => {
let lastTime = currentTimeInMs();
// Note: If there is no template type checker and resource loader, we aren't processing
// an Angular program, and can skip template detection.
if (ts.isClassDeclaration(node) && templateTypeChecker !== null && resourceLoader !== null) {
identifyTemplateReferences(programInfo, node, reflector, checker, evaluator, templateTypeChecker, resourceLoader, programInfo.userOptions, result, knownFields, fieldNamesToConsiderForReferenceLookup);
perfCounters.template += (currentTimeInMs() - lastTime) / 1000;
lastTime = currentTimeInMs();
identifyHostBindingReferences(node, programInfo, checker, reflector, result, knownFields, fieldNamesToConsiderForReferenceLookup);
perfCounters.hostBindings += (currentTimeInMs() - lastTime) / 1000;
lastTime = currentTimeInMs();
}
lastTime = currentTimeInMs();
// find references, but do not capture input declarations itself.
if (ts.isIdentifier(node) &&
!(isInputContainerNode(node.parent) && node.parent.name === node)) {
identifyPotentialTypeScriptReference(node, programInfo, checker, knownFields, result, fieldNamesToConsiderForReferenceLookup, {
debugElComponentInstanceTracker,
});
}
perfCounters.tsReferences += (currentTimeInMs() - lastTime) / 1000;
lastTime = currentTimeInMs();
// Detect `Partial<T>` references.
// Those are relevant to be tracked as they may be updated in Catalyst to
// unwrap signal inputs. Commonly people use `Partial` in Catalyst to type
// some "component initial values".
const partialDirectiveInCatalyst = partialDirectiveCatalystTracker.detect(node);
if (partialDirectiveInCatalyst !== null) {
result.references.push({
kind: exports.ReferenceKind.TsClassTypeReference,
from: {
file: project_paths.projectFile(partialDirectiveInCatalyst.referenceNode.getSourceFile(), programInfo),
node: partialDirectiveInCatalyst.referenceNode,
},
isPartialReference: true,
isPartOfCatalystFile: true,
target: partialDirectiveInCatalyst.targetClass,
});
}
perfCounters.tsTypes += (currentTimeInMs() - lastTime) / 1000;
};
return {
visitor,
debugPrintMetrics: () => {
console.info('Source file analysis performance', perfCounters);
},
};
}
exports.createFindAllSourceFileReferencesVisitor = createFindAllSourceFileReferencesVisitor;
exports.getBindingElementDeclaration = getBindingElementDeclaration;
exports.getMemberName = getMemberName;
exports.isHostBindingReference = isHostBindingReference;
exports.isInputContainerNode = isInputContainerNode;
exports.isTemplateReference = isTemplateReference;
exports.isTsClassTypeReference = isTsClassTypeReference;
exports.isTsReference = isTsReference;
exports.traverseAccess = traverseAccess;
exports.unwrapParent = unwrapParent;

Sorry, the diff of this file is too big to display

+1
-1
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

@@ -1,1 +0,1 @@

{"version":3,"file":"_resource-chunk.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/authoring/output/output_emitter_ref.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/hydration/cache.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/render3/reactivity/computed.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/render3/reactivity/untracked.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/resource/api.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/render3/reactivity/linked_signal.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/resource/resource.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {setActiveConsumer} from '../../../primitives/signals';\n\nimport {inject} from '../../di/injector_compatibility';\nimport {ErrorHandler} from '../../error_handler';\nimport {formatRuntimeError, RuntimeError, RuntimeErrorCode} from '../../errors';\nimport {DestroyRef} from '../../linker/destroy_ref';\n\nimport {OutputRef, OutputRefSubscription} from './output_ref';\n\n/**\n * An `OutputEmitterRef` is created by the `output()` function and can be\n * used to emit values to consumers of your directive or component.\n *\n * Consumers of your directive/component can bind to the output and\n * subscribe to changes via the bound event syntax. For example:\n *\n * ```html\n * <my-comp (valueChange)=\"processNewValue($event)\" />\n * ```\n *\n * @see [Custom events with outputs](guide/components/outputs)\n *\n * @publicAPI\n */\nexport class OutputEmitterRef<T> implements OutputRef<T> {\n private destroyed = false;\n private listeners: Array<(value: T) => void> | null = null;\n private errorHandler = inject(ErrorHandler, {optional: true});\n\n /** @internal */\n destroyRef: DestroyRef = inject(DestroyRef);\n\n constructor() {\n // Clean-up all listeners and mark as destroyed upon destroy.\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.listeners = null;\n });\n }\n\n subscribe(callback: (value: T) => void): OutputRefSubscription {\n if (this.destroyed) {\n throw new RuntimeError(\n RuntimeErrorCode.OUTPUT_REF_DESTROYED,\n ngDevMode &&\n 'Unexpected subscription to destroyed `OutputRef`. ' +\n 'The owning directive/component is destroyed.',\n );\n }\n\n (this.listeners ??= []).push(callback);\n\n return {\n unsubscribe: () => {\n const idx = this.listeners?.indexOf(callback);\n if (idx !== undefined && idx !== -1) {\n this.listeners?.splice(idx, 1);\n }\n },\n };\n }\n\n /** Emits a new value to the output. */\n emit(value: T): void {\n if (this.destroyed) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.OUTPUT_REF_DESTROYED,\n ngDevMode &&\n 'Unexpected emit for destroyed `OutputRef`. ' +\n 'The owning directive/component is destroyed.',\n ),\n );\n return;\n }\n\n if (this.listeners === null) {\n return;\n }\n\n const previousConsumer = setActiveConsumer(null);\n try {\n for (const listenerFn of this.listeners) {\n try {\n listenerFn(value);\n } catch (err: unknown) {\n this.errorHandler?.handleError(err);\n }\n }\n } finally {\n setActiveConsumer(previousConsumer);\n }\n }\n}\n\n/** Gets the owning `DestroyRef` for the given output. */\nexport function getOutputDestroyRef(ref: OutputRef<unknown>): DestroyRef | undefined {\n return ref.destroyRef;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {InjectionToken} from '../di';\n\n/**\n * Token used to the determine if the transfer cache should be used, for example for resources.\n */\nexport const CACHE_ACTIVE = new InjectionToken<{isActive: boolean}>(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'STATE_CACHE_ACTIVE' : '',\n);\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {createComputed, SIGNAL} from '../../../primitives/signals';\n\nimport {Signal, ValueEqualityFn} from './api';\n\n/**\n * Options passed to the `computed` creation function.\n */\nexport interface CreateComputedOptions<T> {\n /**\n * A comparison function which defines equality for computed values.\n */\n equal?: ValueEqualityFn<T>;\n\n /**\n * A debug name for the computed signal. Used in Angular DevTools to identify the signal.\n */\n debugName?: string;\n}\n\n/**\n * Create a computed `Signal` which derives a reactive value from an expression.\n * @see [Computed signals](guide/signals#computed-signals)\n */\nexport function computed<T>(computation: () => T, options?: CreateComputedOptions<T>): Signal<T> {\n const getter = createComputed(computation, options?.equal);\n\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n const debugName = options?.debugName;\n getter[SIGNAL].debugName = debugName;\n getter.toString = () => `[Computed${debugName ? ' (' + debugName + ')' : ''}: ${getter()}]`;\n }\n\n return getter;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {untracked as untrackedPrimitive} from '../../../primitives/signals';\n\n/**\n * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function\n * can, optionally, return a value.\n * @see [Reading without tracking dependencies](guide/signals#reading-without-tracking-dependencies)\n */\nexport function untracked<T>(nonReactiveReadsFn: () => T): T {\n return untrackedPrimitive(nonReactiveReadsFn);\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Injector} from '../di/injector';\nimport {Signal, ValueEqualityFn} from '../render3/reactivity/api';\nimport {WritableSignal} from '../render3/reactivity/signal';\n\n/** Error thrown when a `Resource` dependency of another resource errors. */\nexport class ResourceDependencyError extends Error {\n /** The dependency that errored. */\n readonly dependency: Resource<unknown>;\n\n constructor(dependency: Resource<unknown>) {\n super('Dependency error', {cause: dependency.error()});\n this.name = 'ResourceDependencyError';\n this.dependency = dependency;\n }\n}\n\n/**\n * Special status codes that can be thrown from a resource's `params` or `request` function to\n * indicate that the resource should transition to that status.\n */\nexport class ResourceParamsStatus extends Error {\n private readonly _brand: undefined;\n private constructor(msg: string) {\n super(msg);\n }\n\n /** Status code that transitions the resource to `idle` status. */\n static readonly IDLE = new ResourceParamsStatus('IDLE');\n\n /** Status code that transitions the resource to `loading` status. */\n static readonly LOADING = new ResourceParamsStatus('LOADING');\n}\n\n/** Context received by a resource's `params` or `request` function. */\nexport interface ResourceParamsContext {\n /**\n * Chains the current params off of the value of another resource, returning the value\n * of the other resource if it is available, or propagating the status to the current resource by\n * throwing the appropriate status code if the value is not available.\n */\n readonly chain: <T>(resource: Resource<T>) => T;\n}\n\n/**\n * String value capturing the status of a `Resource`.\n *\n * Possible statuses are:\n *\n * `idle` - The resource has no valid request and will not perform any loading. `value()` will be\n * `undefined`.\n *\n * `loading` - The resource is currently loading a new value as a result of a change in its reactive\n * dependencies. `value()` will be `undefined`.\n *\n * `reloading` - The resource is currently reloading a fresh value for the same reactive\n * dependencies. `value()` will continue to return the previously fetched value during the reloading\n * operation.\n *\n * `error` - Loading failed with an error. `value()` will be `undefined`.\n *\n * `resolved` - Loading has completed and the resource has the value returned from the loader.\n *\n * `local` - The resource's value was set locally via `.set()` or `.update()`.\n *\n * @publicApi 22.0\n */\nexport type ResourceStatus = 'idle' | 'error' | 'loading' | 'reloading' | 'resolved' | 'local';\n\n/**\n * A Resource is an asynchronous dependency (for example, the results of an API call) that is\n * managed and delivered through signals.\n *\n * The usual way of creating a `Resource` is through the `resource` function, but various other APIs\n * may present `Resource` instances to describe their own concepts.\n *\n * @publicApi 22.0\n */\nexport interface Resource<T> {\n /**\n * The current value of the `Resource`, or throws an error if the resource is in an error state.\n */\n readonly value: Signal<T>;\n\n /**\n * The current status of the `Resource`, which describes what the resource is currently doing and\n * what can be expected of its `value`.\n */\n readonly status: Signal<ResourceStatus>;\n\n /**\n * When in the `error` state, this returns the last known error from the `Resource`.\n */\n readonly error: Signal<Error | undefined>;\n\n /**\n * Whether this resource is loading a new value (or reloading the existing one).\n */\n readonly isLoading: Signal<boolean>;\n\n /**\n * The current state of this resource, represented as a `ResourceSnapshot`.\n */\n readonly snapshot: Signal<ResourceSnapshot<T>>;\n\n /**\n * Whether this resource has a valid current value.\n *\n * This function is reactive.\n */\n hasValue(this: T extends undefined ? this : never): this is Resource<Exclude<T, undefined>>;\n\n hasValue(): boolean;\n}\n\n/**\n * A `Resource` with a mutable value.\n *\n * Overwriting the value of a resource sets it to the 'local' state.\n *\n * @publicApi 22.0\n */\nexport interface WritableResource<T> extends Resource<T> {\n readonly value: WritableSignal<T>;\n hasValue(\n this: T extends undefined ? this : never,\n ): this is WritableResource<Exclude<T, undefined>>;\n\n hasValue(): boolean;\n\n /**\n * Convenience wrapper for `value.set`.\n */\n set(value: T): void;\n\n /**\n * Convenience wrapper for `value.update`.\n */\n update(updater: (value: T) => T): void;\n asReadonly(): Resource<T>;\n\n /**\n * Instructs the resource to re-load any asynchronous dependency it may have.\n *\n * Note that the resource will not enter its reloading state until the actual backend request is\n * made.\n *\n * @returns true if a reload was initiated, false if a reload was unnecessary or unsupported\n */\n reload(): boolean;\n}\n\n/**\n * A `WritableResource` created through the `resource` function.\n *\n * @publicApi 22.0\n */\nexport interface ResourceRef<T> extends WritableResource<T> {\n hasValue(this: T extends undefined ? this : never): this is ResourceRef<Exclude<T, undefined>>;\n\n hasValue(): boolean;\n /**\n * Manually destroy the resource, which cancels pending requests and returns it to `idle` state.\n */\n destroy(): void;\n}\n\n/**\n * Parameter to a `ResourceLoader` which gives the request and other options for the current loading\n * operation.\n *\n * @publicApi 22.0\n */\nexport interface ResourceLoaderParams<R> {\n params: NoInfer<Exclude<R, undefined>>;\n abortSignal: AbortSignal;\n previous: {\n status: ResourceStatus;\n };\n}\n\n/**\n * Loading function for a `Resource`.\n *\n * @publicApi 22.0\n */\nexport type ResourceLoader<T, R> = (param: ResourceLoaderParams<R>) => PromiseLike<T>;\n\n/**\n * Streaming loader for a `Resource`.\n *\n * @publicApi 22.0\n */\nexport type ResourceStreamingLoader<T, R> = (\n param: ResourceLoaderParams<R>,\n) => Signal<ResourceStreamItem<T>> | PromiseLike<Signal<ResourceStreamItem<T>>> | undefined;\n\n/**\n * Options to the `resource` function, for creating a resource.\n *\n * @publicApi 22.0\n */\nexport interface BaseResourceOptions<T, R> {\n /**\n * A reactive function which determines the request to be made. Whenever the request changes, the\n * loader will be triggered to fetch a new value for the resource.\n *\n * If a params function isn't provided, the loader won't rerun unless the resource is reloaded.\n */\n params?: (ctx: ResourceParamsContext) => R;\n\n /**\n * The value which will be returned from the resource when a server value is unavailable, such as\n * when the resource is still loading.\n */\n defaultValue?: NoInfer<T>;\n\n /**\n * Equality function used to compare the return value of the loader.\n */\n equal?: ValueEqualityFn<T>;\n\n /**\n * Overrides the `Injector` used by `resource`.\n */\n injector?: Injector;\n\n /**\n * Identifier used to cache the resource data in the `TransferState` during server-side rendering and to retrieve it on the client side.\n * This value value needs to be identical for both the client and server.\n */\n id?: string;\n}\n\n/**\n * Options to the `resource` function, for creating a resource.\n *\n * @publicApi 22.0\n */\nexport interface PromiseResourceOptions<T, R> extends BaseResourceOptions<T, R> {\n /**\n * Loading function which returns a `Promise` of the resource's value for a given request.\n */\n loader: ResourceLoader<T, R>;\n\n /**\n * Cannot specify `stream` and `loader` at the same time.\n */\n stream?: never;\n}\n\n/**\n * Options to the `resource` function, for creating a resource.\n *\n * @publicApi 22.0\n */\nexport interface StreamingResourceOptions<T, R> extends BaseResourceOptions<T, R> {\n /**\n * Loading function which returns a `Promise` of a signal of the resource's value for a given\n * request, which can change over time as new values are received from a stream.\n */\n stream: ResourceStreamingLoader<T, R>;\n\n /**\n * Cannot specify `stream` and `loader` at the same time.\n */\n loader?: never;\n}\n\n/**\n * @publicApi 22.0\n */\nexport type ResourceOptions<T, R> = (\n | PromiseResourceOptions<T, R>\n | StreamingResourceOptions<T, R>\n) & {\n /**\n * A debug name for the reactive node. Used in Angular DevTools to identify the node.\n */\n debugName?: string;\n};\n\n/**\n * @publicApi 22.0\n */\nexport type ResourceStreamItem<T> = {value: T} | {error: Error};\n\n/**\n * An explicit representation of a resource's state.\n *\n * @publicApi 22.0\n * @see [Resource composition with snapshots](guide/signals/resource#resource-composition-with-snapshots)\n */\nexport type ResourceSnapshot<T> =\n | {readonly status: 'idle'; readonly value: T}\n | {readonly status: 'loading' | 'reloading'; readonly value: T}\n | {readonly status: 'resolved' | 'local'; readonly value: T}\n | {readonly status: 'error'; readonly error: Error};\n\n/**\n * Options for `debounced`.\n *\n * @see [Debouncing signals with `debounced`](guide/signals/debounced)\n *\n * @experimental 22.0\n */\nexport interface DebouncedOptions<T> {\n /** The `Injector` to use for the debounced resource. */\n injector?: Injector;\n /** The equality function to use for comparing values. */\n equal?: ValueEqualityFn<T>;\n}\n\n/**\n * Represents the wait condition for item debouncing.\n * Can be a number of milliseconds or a function that returns a Promise.\n *\n * @see [Debouncing signals with `debounced`](guide/signals/debounced)\n *\n * @experimental 22.0\n */\nexport type DebounceTimer<T> =\n | number\n | ((value: T, lastValue: ResourceSnapshot<T>) => Promise<void> | void);\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ComputationFn,\n createLinkedSignal,\n LinkedSignalGetter,\n LinkedSignalNode,\n linkedSignalSetFn,\n linkedSignalUpdateFn,\n SIGNAL,\n} from '../../../primitives/signals';\nimport {Signal, ValueEqualityFn} from './api';\nimport {signalAsReadonlyFn, WritableSignal} from './signal';\n\nconst identityFn = <T>(v: T) => v;\n\n/**\n * Creates a writable signal whose value is initialized and reset by the linked, reactive computation.\n *\n * @publicApi 20.0\n */\nexport function linkedSignal<D>(\n computation: () => D,\n options?: {equal?: ValueEqualityFn<NoInfer<D>>; debugName?: string},\n): WritableSignal<D>;\n\n/**\n * Creates a writable signal whose value is initialized and reset by the linked, reactive computation.\n * This is an advanced API form where the computation has access to the previous value of the signal and the computation result.\n *\n * Note: The computation is reactive, meaning the linked signal will automatically update whenever any of the signals used within the computation change.\n *\n * @publicApi 20.0\n * @see [Dependent state with linkedSignal](guide/signals/linked-signal)\n */\nexport function linkedSignal<S, D>(options: {\n source: () => S;\n computation: (source: NoInfer<S>, previous?: {source: NoInfer<S>; value: NoInfer<D>}) => D;\n equal?: ValueEqualityFn<NoInfer<D>>;\n debugName?: string;\n}): WritableSignal<D>;\n\nexport function linkedSignal<S, D>(\n optionsOrComputation:\n | {\n source: () => S;\n computation: ComputationFn<S, D>;\n equal?: ValueEqualityFn<D>;\n debugName?: string;\n }\n | (() => D),\n options?: {equal?: ValueEqualityFn<D>; debugName?: string},\n): WritableSignal<D> {\n if (typeof optionsOrComputation === 'function') {\n const getter = createLinkedSignal<D, D>(\n optionsOrComputation,\n identityFn<D>,\n options?.equal,\n ) as LinkedSignalGetter<D, D> & WritableSignal<D>;\n return upgradeLinkedSignalGetter(getter, options?.debugName);\n } else {\n const getter = createLinkedSignal<S, D>(\n optionsOrComputation.source,\n optionsOrComputation.computation,\n optionsOrComputation.equal,\n );\n return upgradeLinkedSignalGetter(getter, optionsOrComputation.debugName);\n }\n}\n\nfunction upgradeLinkedSignalGetter<S, D>(\n getter: LinkedSignalGetter<S, D>,\n debugName?: string,\n): WritableSignal<D> {\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n getter[SIGNAL].debugName = debugName;\n getter.toString = () => `[LinkedSignal${debugName ? ' (' + debugName + ')' : ''}: ${getter()}]`;\n }\n\n const node = getter[SIGNAL] as LinkedSignalNode<S, D>;\n const upgradedGetter = getter as LinkedSignalGetter<S, D> & WritableSignal<D>;\n\n upgradedGetter.set = (newValue: D) => linkedSignalSetFn(node, newValue);\n upgradedGetter.update = (updateFn: (value: D) => D) => linkedSignalUpdateFn(node, updateFn);\n upgradedGetter.asReadonly = signalAsReadonlyFn.bind(getter as any) as () => Signal<D>;\n\n return upgradedGetter;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {isSignal, Signal, ValueEqualityFn} from '../render3/reactivity/api';\nimport {computed} from '../render3/reactivity/computed';\nimport {effect, EffectRef} from '../render3/reactivity/effect';\nimport {signal, signalAsReadonlyFn, WritableSignal} from '../render3/reactivity/signal';\nimport {untracked} from '../render3/reactivity/untracked';\nimport {\n Resource,\n ResourceDependencyError,\n ResourceOptions,\n ResourceParamsStatus,\n ResourceSnapshot,\n ResourceStatus,\n ResourceStreamingLoader,\n ResourceStreamItem,\n StreamingResourceOptions,\n type ResourceParamsContext,\n type ResourceRef,\n type WritableResource,\n} from './api';\n\nimport {assertInInjectionContext} from '../di/contextual';\nimport {Injector} from '../di/injector';\nimport {inject} from '../di/injector_compatibility';\nimport {RuntimeError, RuntimeErrorCode} from '../errors';\nimport {CACHE_ACTIVE} from '../hydration/cache';\nimport {DestroyRef} from '../linker/destroy_ref';\nimport {PendingTasks} from '../pending_tasks';\nimport {linkedSignal} from '../render3/reactivity/linked_signal';\nimport {StateKey, TransferState} from '../transfer_state';\n\n/**\n * Constructs a `Resource` that projects a reactive request to an asynchronous operation defined by\n * a loader function, which exposes the result of the loading operation via signals.\n *\n * Note that `resource` is intended for _read_ operations, not operations which perform mutations.\n * `resource` will cancel in-progress loads via the `AbortSignal` when destroyed or when a new\n * request object becomes available, which could prematurely abort mutations.\n *\n * @see [Async reactivity with resources](guide/signals/resource)\n *\n * @experimental 19.0\n */\nexport function resource<T, R>(\n options: ResourceOptions<T, R> & {defaultValue: NoInfer<T>},\n): ResourceRef<T>;\n\n/**\n * Constructs a `Resource` that projects a reactive request to an asynchronous operation defined by\n * a loader function, which exposes the result of the loading operation via signals.\n *\n * Note that `resource` is intended for _read_ operations, not operations which perform mutations.\n * `resource` will cancel in-progress loads via the `AbortSignal` when destroyed or when a new\n * request object becomes available, which could prematurely abort mutations.\n *\n * @experimental 19.0\n * @see [Async reactivity with resources](guide/signals/resource)\n */\nexport function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined>;\nexport function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined> {\n if (ngDevMode && !options?.injector) {\n assertInInjectionContext(resource);\n }\n\n const oldNameForParams = (\n options as ResourceOptions<T, R> & {request: ResourceOptions<T, R>['params']}\n ).request;\n const params = options.params ?? oldNameForParams ?? (() => null!);\n return new ResourceImpl<T | undefined, R>(\n params,\n getLoader(options),\n options.defaultValue,\n options.equal ? wrapEqualityFn(options.equal) : undefined,\n options.debugName,\n options.injector ?? inject(Injector),\n options.id as StateKey<T>,\n );\n}\n\ntype ResourceInternalStatus = 'idle' | 'loading' | 'resolved' | 'local';\n\n/**\n * Internal state of a resource.\n */\ninterface ResourceProtoState<T> {\n extRequest: WrappedRequest;\n\n // For simplicity, status is internally tracked as a subset of the public status enum.\n // Reloading and Error statuses are projected from Loading and Resolved based on other state.\n status: ResourceInternalStatus;\n}\n\ninterface ResourceState<T> extends ResourceProtoState<T> {\n previousStatus: ResourceStatus;\n stream: Signal<ResourceStreamItem<T>> | undefined;\n}\n\ntype WrappedRequest = {\n request?: unknown;\n reload: number;\n status?: ResourceInternalStatus;\n error?: Error;\n};\n\n/**\n * Base class which implements `.value` as a `WritableSignal` by delegating `.set` and `.update`.\n */\nabstract class BaseWritableResource<T> implements WritableResource<T> {\n readonly value: WritableSignal<T>;\n abstract readonly status: Signal<ResourceStatus>;\n abstract readonly error: Signal<Error | undefined>;\n\n abstract reload(): boolean;\n\n readonly isLoading: Signal<boolean>;\n\n constructor(value: Signal<T>, debugName: string | undefined) {\n this.value = value as WritableSignal<T>;\n this.value.set = this.set.bind(this);\n this.value.update = this.update.bind(this);\n this.value.asReadonly = signalAsReadonlyFn;\n\n this.isLoading = computed(\n () => this.status() === 'loading' || this.status() === 'reloading',\n ngDevMode ? createDebugNameObject(debugName, 'isLoading') : undefined,\n );\n }\n\n abstract set(value: T): void;\n\n private readonly isError = computed(() => this.status() === 'error');\n\n update(updateFn: (value: T) => T): void {\n this.set(updateFn(untracked(this.value)));\n }\n\n // Use a computed here to avoid triggering reactive consumers if the value changes while staying\n // either defined or undefined.\n private readonly isValueDefined = computed(() => {\n // Check if it's in an error state first to prevent the error from bubbling up.\n if (this.isError()) {\n return false;\n }\n\n return this.value() !== undefined;\n });\n\n private _snapshot: Signal<ResourceSnapshot<T>> | undefined;\n get snapshot(): Signal<ResourceSnapshot<T>> {\n return (this._snapshot ??= computed(() => {\n const status = this.status();\n if (status === 'error') {\n return {status: 'error', error: this.error()!};\n } else {\n return {status, value: this.value()};\n }\n }));\n }\n\n hasValue(): this is ResourceRef<Exclude<T, undefined>> {\n return this.isValueDefined();\n }\n\n asReadonly(): Resource<T> {\n return this;\n }\n}\n\n/**\n * Implementation for `resource()` which uses a `linkedSignal` to manage the resource's state.\n */\nexport class ResourceImpl<T, R> extends BaseWritableResource<T> implements ResourceRef<T> {\n private readonly pendingTasks: PendingTasks;\n\n /**\n * The current state of the resource. Status, value, and error are derived from this.\n */\n private readonly state: WritableSignal<ResourceState<T>>;\n\n /**\n * Combines the current request with a reload counter which allows the resource to be reloaded on\n * imperative command.\n */\n protected readonly extRequest: WritableSignal<WrappedRequest>;\n private readonly effectRef: EffectRef;\n\n private pendingController: AbortController | undefined;\n private resolvePendingTask: (() => void) | undefined = undefined;\n private destroyed = false;\n private unregisterOnDestroy: () => void;\n\n override readonly status: Signal<ResourceStatus>;\n override readonly error: Signal<Error | undefined>;\n private readonly transferState: TransferState | undefined;\n\n constructor(\n request: (ctx: ResourceParamsContext) => R,\n private readonly loaderFn: ResourceStreamingLoader<T, R>,\n defaultValue: T,\n private readonly equal: ValueEqualityFn<T> | undefined,\n private readonly debugName: string | undefined,\n injector: Injector,\n private transferCacheKey: StateKey<T> | undefined,\n getInitialStream?: (request: R) => Signal<ResourceStreamItem<T>> | undefined,\n ) {\n if (isInParamsFunction()) {\n throw invalidResourceCreationInParams();\n }\n\n super(\n // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a\n // `WritableSignal` that delegates to `ResourceImpl.set`.\n computed(\n () => {\n const streamValue = this.state().stream?.();\n\n if (!streamValue) {\n return defaultValue;\n }\n\n // Prevents `hasValue()` from throwing an error when a reload happened in the error state\n if (this.state().status === 'loading' && this.error()) {\n return defaultValue;\n }\n\n if (!isResolved(streamValue)) {\n throw new ResourceValueError(this.error()!);\n }\n\n return streamValue.value;\n },\n {equal, ...(ngDevMode ? createDebugNameObject(debugName, 'value') : undefined)},\n ),\n debugName,\n );\n\n const cacheState = injector.get(CACHE_ACTIVE, undefined, {optional: true}) ?? {isActive: false};\n\n this.transferState = injector.get(TransferState, undefined, {optional: true}) ?? undefined;\n\n this.extRequest = linkedSignal<WrappedRequest>(\n () => {\n try {\n setInParamsFunction(true);\n return {request: request(paramsContext), reload: 0};\n } catch (error) {\n rethrowFatalErrors(error);\n if (error === ResourceParamsStatus.IDLE) {\n return {status: 'idle', reload: 0};\n } else if (error === ResourceParamsStatus.LOADING) {\n return {status: 'loading', reload: 0};\n }\n return {error: error as Error, reload: 0};\n } finally {\n setInParamsFunction(false);\n }\n },\n ngDevMode ? createDebugNameObject(debugName, 'extRequest') : undefined,\n );\n\n // The main resource state is managed in a `linkedSignal`, which allows the resource to change\n // state instantaneously when the request signal changes.\n this.state = linkedSignal<WrappedRequest, ResourceState<T>>({\n // Whenever the request changes,\n source: this.extRequest,\n // Compute the state of the resource given a change in status.\n computation: (extRequest, previous) => {\n let {request, status, error} = extRequest;\n let stream: Signal<ResourceStreamItem<T>> | undefined;\n\n if (error) {\n status = 'resolved';\n stream = signal(\n {error: encapsulateResourceError(error)},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n );\n } else if (!status) {\n if (!previous) {\n const transferState = this.transferState;\n const cacheKey = this.transferCacheKey;\n if (cacheState.isActive && cacheKey && transferState && request !== undefined) {\n const key = this.transferCacheKey;\n if (transferState.hasKey(cacheKey)) {\n stream = signal(\n {value: transferState.get(cacheKey, defaultValue)},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n );\n }\n }\n\n if (!stream) {\n stream = getInitialStream?.(extRequest.request as R);\n }\n // Clear getInitialStream so it doesn't hold onto memory\n getInitialStream = undefined;\n status = request === undefined ? 'idle' : stream ? 'resolved' : 'loading';\n } else {\n status = request === undefined ? 'idle' : 'loading';\n if (previous.value.extRequest.request === request) {\n stream = previous.value.stream;\n }\n }\n }\n\n return {\n extRequest,\n status,\n previousStatus: previous ? projectStatusOfState(previous.value) : 'idle',\n stream,\n };\n },\n ...(ngDevMode ? createDebugNameObject(debugName, 'state') : undefined),\n });\n\n this.effectRef = effect(this.loadEffect.bind(this), {\n injector,\n manualCleanup: true,\n ...(ngDevMode ? createDebugNameObject(debugName, 'loadEffect') : undefined),\n });\n\n this.pendingTasks = injector.get(PendingTasks);\n\n // Cancel any pending request when the resource itself is destroyed.\n this.unregisterOnDestroy = injector.get(DestroyRef).onDestroy(() => this.destroy());\n\n this.status = computed(\n () => projectStatusOfState(this.state()),\n ngDevMode ? createDebugNameObject(debugName, 'status') : undefined,\n );\n\n this.error = computed(\n () => {\n const stream = this.state().stream?.();\n return stream && !isResolved(stream) ? stream.error : undefined;\n },\n ngDevMode ? createDebugNameObject(debugName, 'error') : undefined,\n );\n }\n\n /**\n * Called either directly via `WritableResource.set` or via `.value.set()`.\n */\n override set(value: T): void {\n if (this.destroyed) {\n return;\n }\n\n const error = untracked(this.error);\n const state = untracked(this.state);\n\n if (!error) {\n const current = untracked(this.value);\n if (\n state.status === 'local' &&\n (this.equal ? this.equal(current, value) : current === value)\n ) {\n return;\n }\n }\n\n // Enter Local state with the user-defined value.\n this.state.set({\n extRequest: state.extRequest,\n status: 'local',\n previousStatus: 'local',\n stream: signal(\n {value},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n ),\n });\n\n // We're departing from whatever state the resource was in previously, so cancel any in-progress\n // loading operations.\n this.abortInProgressLoad();\n }\n\n override reload(): boolean {\n // We don't want to restart in-progress loads.\n const {status} = untracked(this.state);\n if (status === 'idle' || status === 'loading') {\n return false;\n }\n\n // Increment the request reload to trigger the `state` linked signal to switch us to `Reload`\n this.extRequest.update(({request, reload}) => ({request, reload: reload + 1}));\n return true;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.unregisterOnDestroy();\n this.effectRef.destroy();\n this.abortInProgressLoad();\n\n // Destroyed resources enter Idle state.\n this.state.set({\n extRequest: {request: undefined, reload: 0},\n status: 'idle',\n previousStatus: 'idle',\n stream: undefined,\n });\n }\n\n private async loadEffect(): Promise<void> {\n const extRequest = this.extRequest();\n\n // Capture the previous status before any state transitions. Note that this is `untracked` since\n // we do not want the effect to depend on the state of the resource, only on the request.\n const {status: currentStatus, previousStatus} = untracked(this.state);\n\n if (extRequest.request === undefined) {\n // Nothing to load (and we should already be in a non-loading state).\n return;\n } else if (currentStatus !== 'loading') {\n // We're not in a loading or reloading state, so this loading request is stale.\n return;\n }\n\n // Cancel any previous loading attempts.\n this.abortInProgressLoad();\n\n // Capturing _this_ load's pending task in a local variable is important here. We may attempt to\n // resolve it twice:\n //\n // 1. when the loading function promise resolves/rejects\n // 2. when cancelling the loading operation\n //\n // After the loading operation is cancelled, `this.resolvePendingTask` no longer represents this\n // particular task, but this `await` may eventually resolve/reject. Thus, when we cancel in\n // response to (1) below, we need to cancel the locally saved task.\n let resolvePendingTask: (() => void) | undefined = (this.resolvePendingTask =\n this.pendingTasks.add());\n\n const {signal: abortSignal} = (this.pendingController = new AbortController());\n\n try {\n // The actual loading is run through `untracked` - only the request side of `resource` is\n // reactive. This avoids any confusion with signals tracking or not tracking depending on\n // which side of the `await` they are.\n const stream = untracked(() => {\n return this.loaderFn({\n params: extRequest.request as Exclude<R, undefined>,\n abortSignal,\n previous: {\n status: previousStatus,\n },\n });\n });\n\n // If this request has been aborted, or the current request no longer\n // matches this load, then we should ignore this resolution.\n const shouldDiscard = () => abortSignal.aborted || untracked(this.extRequest) !== extRequest;\n\n if (isSignal(stream)) {\n if (shouldDiscard()) {\n return;\n }\n\n this.state.set({\n extRequest,\n status: 'resolved',\n previousStatus: 'resolved',\n stream,\n });\n\n const result = untracked(stream);\n if (typeof ngServerMode !== 'undefined' && ngServerMode) {\n saveToTransferState(result, this.transferCacheKey, this.transferState);\n }\n } else {\n const resolvedStream = await stream;\n if (shouldDiscard()) {\n return;\n }\n\n this.state.set({\n extRequest,\n status: 'resolved',\n previousStatus: 'resolved',\n stream: resolvedStream,\n });\n\n // Use a local variable for the result so TypeScript can narrow `resolvedStream` correctly.\n const result = resolvedStream ? untracked(resolvedStream) : undefined;\n if (typeof ngServerMode !== 'undefined' && ngServerMode) {\n saveToTransferState(result, this.transferCacheKey, this.transferState);\n }\n }\n } catch (err) {\n rethrowFatalErrors(err);\n if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {\n return;\n }\n\n this.state.set({\n extRequest,\n status: 'resolved',\n previousStatus: 'error',\n stream: signal(\n {error: encapsulateResourceError(err)},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n ),\n });\n } finally {\n // Resolve the pending task now that the resource has a value.\n resolvePendingTask?.();\n resolvePendingTask = undefined;\n }\n }\n\n private abortInProgressLoad(): void {\n untracked(() => this.pendingController?.abort());\n this.pendingController = undefined;\n\n // Once the load is aborted, we no longer want to block stability on its resolution.\n this.resolvePendingTask?.();\n this.resolvePendingTask = undefined;\n }\n}\n\nfunction saveToTransferState<R, T>(\n result: ResourceStreamItem<T> | undefined,\n transferCacheKey: StateKey<T> | undefined,\n transferState: TransferState | undefined,\n): void {\n if (transferCacheKey && transferState && result && isResolved(result)) {\n transferState.set(transferCacheKey, result.value);\n }\n}\n\n/**\n * Wraps an equality function to handle either value being `undefined`.\n */\nfunction wrapEqualityFn<T>(equal: ValueEqualityFn<T>): ValueEqualityFn<T | undefined> {\n return (a, b) => (a === undefined || b === undefined ? a === b : equal(a, b));\n}\n\nfunction getLoader<T, R>(options: ResourceOptions<T, R>): ResourceStreamingLoader<T, R> {\n if (isStreamingResourceOptions(options)) {\n return options.stream;\n }\n\n return async (params) => {\n try {\n return signal(\n {value: await options.loader(params)},\n ngDevMode ? createDebugNameObject(options.debugName, 'stream') : undefined,\n );\n } catch (err) {\n return signal(\n {error: encapsulateResourceError(err)},\n ngDevMode ? createDebugNameObject(options.debugName, 'stream') : undefined,\n );\n }\n };\n}\n\nfunction isStreamingResourceOptions<T, R>(\n options: ResourceOptions<T, R>,\n): options is StreamingResourceOptions<T, R> {\n return !!(options as StreamingResourceOptions<T, R>).stream;\n}\n\n/**\n * Project from a state with `ResourceInternalStatus` to the user-facing `ResourceStatus`\n */\nfunction projectStatusOfState(state: ResourceState<unknown>): ResourceStatus {\n switch (state.status) {\n case 'loading':\n return state.extRequest.reload === 0 ? 'loading' : 'reloading';\n case 'resolved':\n return isResolved(state.stream!()) ? 'resolved' : 'error';\n default:\n return state.status;\n }\n}\n\nfunction isResolved<T>(state: ResourceStreamItem<T>): state is {value: T} {\n return (state as {error: unknown}).error === undefined;\n}\n\n/**\n * Creates a debug name object for an internal signal.\n */\nfunction createDebugNameObject(\n resourceDebugName: string | undefined,\n internalSignalDebugName: string,\n): {debugName?: string} {\n return {\n debugName: `Resource${resourceDebugName ? '#' + resourceDebugName : ''}.${internalSignalDebugName}`,\n };\n}\n\nexport function encapsulateResourceError(error: unknown): Error {\n if (isErrorLike(error)) {\n return error;\n }\n\n return new ResourceWrappedError(error);\n}\n\nexport function isErrorLike(error: unknown): error is Error {\n return (\n error instanceof Error ||\n (typeof error === 'object' &&\n typeof (error as Error).name === 'string' &&\n typeof (error as Error).message === 'string')\n );\n}\n\nexport class ResourceValueError extends Error {\n constructor(error: Error) {\n super(\n ngDevMode\n ? `Resource is currently in an error state (see Error.cause for details): ${error.message}`\n : error.message,\n {cause: error},\n );\n }\n}\n\nclass ResourceWrappedError extends Error {\n constructor(error: unknown) {\n super(\n ngDevMode\n ? `Resource returned an error that's not an Error instance: ${String(error)}. Check this error's .cause for the actual error.`\n : String(error),\n {cause: error},\n );\n }\n}\n\n/**\n * Chains the value of another resource into the params of the current resource, returning the value\n * of the other resource if it is available, or propagating the status to the current resource if it\n * is not.\n */\nexport function chain<T>(resource: Resource<T>): T {\n switch (resource.status()) {\n case 'idle':\n throw ResourceParamsStatus.IDLE;\n case 'error':\n throw new ResourceDependencyError(resource);\n case 'loading':\n case 'reloading':\n throw ResourceParamsStatus.LOADING;\n }\n return resource.value();\n}\n\nexport const paramsContext: ResourceParamsContext = {\n chain,\n};\n\nlet inParamsFunction = false;\n\nexport function isInParamsFunction() {\n return inParamsFunction;\n}\n\nexport function setInParamsFunction(value: boolean) {\n inParamsFunction = value;\n}\n\nexport function invalidResourceCreationInParams(): Error {\n return new RuntimeError(\n RuntimeErrorCode.INVALID_RESOURCE_CREATION_IN_PARAMS,\n ngDevMode && `Cannot create a resource inside the \\`params\\` of another resource`,\n );\n}\n\nexport function rethrowFatalErrors(error: unknown) {\n if (\n error instanceof RuntimeError &&\n error.code === RuntimeErrorCode.INVALID_RESOURCE_CREATION_IN_PARAMS\n ) {\n throw error;\n }\n}\n"],"names":["OutputEmitterRef","destroyed","listeners","errorHandler","inject","ErrorHandler","optional","destroyRef","DestroyRef","constructor","onDestroy","subscribe","callback","RuntimeError","ngDevMode","push","unsubscribe","idx","indexOf","undefined","splice","emit","value","console","warn","formatRuntimeError","previousConsumer","setActiveConsumer","listenerFn","err","handleError","getOutputDestroyRef","ref","CACHE_ACTIVE","InjectionToken","computed","computation","options","getter","createComputed","equal","debugName","SIGNAL","toString","untracked","nonReactiveReadsFn","untrackedPrimitive","ResourceDependencyError","Error","dependency","cause","error","name","ResourceParamsStatus","_brand","msg","IDLE","LOADING","identityFn","v","linkedSignal","optionsOrComputation","createLinkedSignal","upgradeLinkedSignalGetter","source","node","upgradedGetter","set","newValue","linkedSignalSetFn","update","updateFn","linkedSignalUpdateFn","asReadonly","signalAsReadonlyFn","bind","resource","injector","assertInInjectionContext","oldNameForParams","request","params","ResourceImpl","getLoader","defaultValue","wrapEqualityFn","Injector","id","BaseWritableResource","isLoading","status","createDebugNameObject","isError","isValueDefined","_snapshot","snapshot","hasValue","loaderFn","transferCacheKey","pendingTasks","state","extRequest","effectRef","pendingController","resolvePendingTask","unregisterOnDestroy","transferState","getInitialStream","isInParamsFunction","invalidResourceCreationInParams","streamValue","stream","isResolved","ResourceValueError","cacheState","get","isActive","TransferState","setInParamsFunction","paramsContext","reload","rethrowFatalErrors","previous","signal","encapsulateResourceError","cacheKey","hasKey","previousStatus","projectStatusOfState","effect","loadEffect","manualCleanup","PendingTasks","destroy","current","abortInProgressLoad","currentStatus","add","abortSignal","AbortController","shouldDiscard","aborted","isSignal","result","ngServerMode","saveToTransferState","resolvedStream","abort","a","b","isStreamingResourceOptions","loader","resourceDebugName","internalSignalDebugName","isErrorLike","ResourceWrappedError","message","String","chain","inParamsFunction","code"],"mappings":"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"}
{"version":3,"file":"_resource-chunk.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/authoring/output/output_emitter_ref.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/hydration/cache.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/render3/reactivity/computed.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/render3/reactivity/untracked.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/resource/api.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/render3/reactivity/linked_signal.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/packages/core/src/resource/resource.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {setActiveConsumer} from '../../../primitives/signals';\n\nimport {inject} from '../../di/injector_compatibility';\nimport {ErrorHandler} from '../../error_handler';\nimport {formatRuntimeError, RuntimeError, RuntimeErrorCode} from '../../errors';\nimport {DestroyRef} from '../../linker/destroy_ref';\n\nimport {OutputRef, OutputRefSubscription} from './output_ref';\n\n/**\n * An `OutputEmitterRef` is created by the `output()` function and can be\n * used to emit values to consumers of your directive or component.\n *\n * Consumers of your directive/component can bind to the output and\n * subscribe to changes via the bound event syntax. For example:\n *\n * ```html\n * <my-comp (valueChange)=\"processNewValue($event)\" />\n * ```\n *\n * @see [Custom events with outputs](guide/components/outputs)\n *\n * @publicAPI\n */\nexport class OutputEmitterRef<T> implements OutputRef<T> {\n private destroyed = false;\n private listeners: Array<(value: T) => void> | null = null;\n private errorHandler = inject(ErrorHandler, {optional: true});\n\n /** @internal */\n destroyRef: DestroyRef = inject(DestroyRef);\n\n constructor() {\n // Clean-up all listeners and mark as destroyed upon destroy.\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.listeners = null;\n });\n }\n\n subscribe(callback: (value: T) => void): OutputRefSubscription {\n if (this.destroyed) {\n throw new RuntimeError(\n RuntimeErrorCode.OUTPUT_REF_DESTROYED,\n ngDevMode &&\n 'Unexpected subscription to destroyed `OutputRef`. ' +\n 'The owning directive/component is destroyed.',\n );\n }\n\n (this.listeners ??= []).push(callback);\n\n return {\n unsubscribe: () => {\n const idx = this.listeners?.indexOf(callback);\n if (idx !== undefined && idx !== -1) {\n this.listeners?.splice(idx, 1);\n }\n },\n };\n }\n\n /** Emits a new value to the output. */\n emit(value: T): void {\n if (this.destroyed) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.OUTPUT_REF_DESTROYED,\n ngDevMode &&\n 'Unexpected emit for destroyed `OutputRef`. ' +\n 'The owning directive/component is destroyed.',\n ),\n );\n return;\n }\n\n if (this.listeners === null) {\n return;\n }\n\n const previousConsumer = setActiveConsumer(null);\n try {\n for (const listenerFn of this.listeners) {\n try {\n listenerFn(value);\n } catch (err: unknown) {\n this.errorHandler?.handleError(err);\n }\n }\n } finally {\n setActiveConsumer(previousConsumer);\n }\n }\n}\n\n/** Gets the owning `DestroyRef` for the given output. */\nexport function getOutputDestroyRef(ref: OutputRef<unknown>): DestroyRef | undefined {\n return ref.destroyRef;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {InjectionToken} from '../di';\n\n/**\n * Token used to the determine if the transfer cache should be used, for example for resources.\n */\nexport const CACHE_ACTIVE = new InjectionToken<{isActive: boolean}>(\n typeof ngDevMode !== 'undefined' && ngDevMode ? 'STATE_CACHE_ACTIVE' : '',\n);\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {createComputed, SIGNAL} from '../../../primitives/signals';\n\nimport {Signal, ValueEqualityFn} from './api';\n\n/**\n * Options passed to the `computed` creation function.\n */\nexport interface CreateComputedOptions<T> {\n /**\n * A comparison function which defines equality for computed values.\n */\n equal?: ValueEqualityFn<T>;\n\n /**\n * A debug name for the computed signal. Used in Angular DevTools to identify the signal.\n */\n debugName?: string;\n}\n\n/**\n * Create a computed `Signal` which derives a reactive value from an expression.\n * @see [Computed signals](guide/signals#computed-signals)\n */\nexport function computed<T>(computation: () => T, options?: CreateComputedOptions<T>): Signal<T> {\n const getter = createComputed(computation, options?.equal);\n\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n const debugName = options?.debugName;\n getter[SIGNAL].debugName = debugName;\n getter.toString = () => `[Computed${debugName ? ' (' + debugName + ')' : ''}: ${getter()}]`;\n }\n\n return getter;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {untracked as untrackedPrimitive} from '../../../primitives/signals';\n\n/**\n * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function\n * can, optionally, return a value.\n * @see [Reading without tracking dependencies](guide/signals#reading-without-tracking-dependencies)\n */\nexport function untracked<T>(nonReactiveReadsFn: () => T): T {\n return untrackedPrimitive(nonReactiveReadsFn);\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Injector} from '../di/injector';\nimport {Signal, ValueEqualityFn} from '../render3/reactivity/api';\nimport {WritableSignal} from '../render3/reactivity/signal';\n\n/** Error thrown when a `Resource` dependency of another resource errors. */\nexport class ResourceDependencyError extends Error {\n /** The dependency that errored. */\n readonly dependency: Resource<unknown>;\n\n constructor(dependency: Resource<unknown>) {\n super('Dependency error', {cause: dependency.error()});\n this.name = 'ResourceDependencyError';\n this.dependency = dependency;\n }\n}\n\n/**\n * Special status codes that can be thrown from a resource's `params` or `request` function to\n * indicate that the resource should transition to that status.\n */\nexport class ResourceParamsStatus extends Error {\n private readonly _brand: undefined;\n private constructor(msg: string) {\n super(msg);\n }\n\n /** Status code that transitions the resource to `idle` status. */\n static readonly IDLE = new ResourceParamsStatus('IDLE');\n\n /** Status code that transitions the resource to `loading` status. */\n static readonly LOADING = new ResourceParamsStatus('LOADING');\n}\n\n/** Context received by a resource's `params` or `request` function. */\nexport interface ResourceParamsContext {\n /**\n * Chains the current params off of the value of another resource, returning the value\n * of the other resource if it is available, or propagating the status to the current resource by\n * throwing the appropriate status code if the value is not available.\n */\n readonly chain: <T>(resource: Resource<T>) => T;\n}\n\n/**\n * String value capturing the status of a `Resource`.\n *\n * Possible statuses are:\n *\n * `idle` - The resource has no valid request and will not perform any loading. `value()` will be\n * `undefined`.\n *\n * `loading` - The resource is currently loading a new value as a result of a change in its reactive\n * dependencies. `value()` will be `undefined`.\n *\n * `reloading` - The resource is currently reloading a fresh value for the same reactive\n * dependencies. `value()` will continue to return the previously fetched value during the reloading\n * operation.\n *\n * `error` - Loading failed with an error. `value()` will be `undefined`.\n *\n * `resolved` - Loading has completed and the resource has the value returned from the loader.\n *\n * `local` - The resource's value was set locally via `.set()` or `.update()`.\n *\n * @publicApi 22.0\n */\nexport type ResourceStatus = 'idle' | 'error' | 'loading' | 'reloading' | 'resolved' | 'local';\n\n/**\n * A Resource is an asynchronous dependency (for example, the results of an API call) that is\n * managed and delivered through signals.\n *\n * The usual way of creating a `Resource` is through the `resource` function, but various other APIs\n * may present `Resource` instances to describe their own concepts.\n *\n * @publicApi 22.0\n */\nexport interface Resource<T> {\n /**\n * The current value of the `Resource`, or throws an error if the resource is in an error state.\n */\n readonly value: Signal<T>;\n\n /**\n * The current status of the `Resource`, which describes what the resource is currently doing and\n * what can be expected of its `value`.\n */\n readonly status: Signal<ResourceStatus>;\n\n /**\n * When in the `error` state, this returns the last known error from the `Resource`.\n */\n readonly error: Signal<Error | undefined>;\n\n /**\n * Whether this resource is loading a new value (or reloading the existing one).\n */\n readonly isLoading: Signal<boolean>;\n\n /**\n * The current state of this resource, represented as a `ResourceSnapshot`.\n */\n readonly snapshot: Signal<ResourceSnapshot<T>>;\n\n /**\n * Whether this resource has a valid current value.\n *\n * This function is reactive.\n */\n hasValue(this: T extends undefined ? this : never): this is Resource<Exclude<T, undefined>>;\n\n hasValue(): boolean;\n}\n\n/**\n * A `Resource` with a mutable value.\n *\n * Overwriting the value of a resource sets it to the 'local' state.\n *\n * @publicApi 22.0\n */\nexport interface WritableResource<T> extends Resource<T> {\n readonly value: WritableSignal<T>;\n hasValue(\n this: T extends undefined ? this : never,\n ): this is WritableResource<Exclude<T, undefined>>;\n\n hasValue(): boolean;\n\n /**\n * Convenience wrapper for `value.set`.\n */\n set(value: T): void;\n\n /**\n * Convenience wrapper for `value.update`.\n */\n update(updater: (value: T) => T): void;\n asReadonly(): Resource<T>;\n\n /**\n * Instructs the resource to re-load any asynchronous dependency it may have.\n *\n * Note that the resource will not enter its reloading state until the actual backend request is\n * made.\n *\n * @returns true if a reload was initiated, false if a reload was unnecessary or unsupported\n */\n reload(): boolean;\n}\n\n/**\n * A `WritableResource` created through the `resource` function.\n *\n * @publicApi 22.0\n */\nexport interface ResourceRef<T> extends WritableResource<T> {\n hasValue(this: T extends undefined ? this : never): this is ResourceRef<Exclude<T, undefined>>;\n\n hasValue(): boolean;\n /**\n * Manually destroy the resource, which cancels pending requests and returns it to `idle` state.\n */\n destroy(): void;\n}\n\n/**\n * Parameter to a `ResourceLoader` which gives the request and other options for the current loading\n * operation.\n *\n * @publicApi 22.0\n */\nexport interface ResourceLoaderParams<R> {\n params: NoInfer<Exclude<R, undefined>>;\n abortSignal: AbortSignal;\n previous: {\n status: ResourceStatus;\n };\n}\n\n/**\n * Loading function for a `Resource`.\n *\n * @publicApi 22.0\n */\nexport type ResourceLoader<T, R> = (param: ResourceLoaderParams<R>) => PromiseLike<T>;\n\n/**\n * Streaming loader for a `Resource`.\n *\n * @publicApi 22.0\n */\nexport type ResourceStreamingLoader<T, R> = (\n param: ResourceLoaderParams<R>,\n) => Signal<ResourceStreamItem<T>> | PromiseLike<Signal<ResourceStreamItem<T>>> | undefined;\n\n/**\n * Options to the `resource` function, for creating a resource.\n *\n * @publicApi 22.0\n */\nexport interface BaseResourceOptions<T, R> {\n /**\n * A reactive function which determines the request to be made. Whenever the request changes, the\n * loader will be triggered to fetch a new value for the resource.\n *\n * If a params function isn't provided, the loader won't rerun unless the resource is reloaded.\n */\n params?: (ctx: ResourceParamsContext) => R;\n\n /**\n * The value which will be returned from the resource when a server value is unavailable, such as\n * when the resource is still loading.\n */\n defaultValue?: NoInfer<T>;\n\n /**\n * Equality function used to compare the return value of the loader.\n */\n equal?: ValueEqualityFn<T>;\n\n /**\n * Overrides the `Injector` used by `resource`.\n */\n injector?: Injector;\n\n /**\n * Identifier used to cache the resource data in the `TransferState` during server-side rendering and to retrieve it on the client side.\n * This value value needs to be identical for both the client and server.\n */\n id?: string;\n}\n\n/**\n * Options to the `resource` function, for creating a resource.\n *\n * @publicApi 22.0\n */\nexport interface PromiseResourceOptions<T, R> extends BaseResourceOptions<T, R> {\n /**\n * Loading function which returns a `Promise` of the resource's value for a given request.\n */\n loader: ResourceLoader<T, R>;\n\n /**\n * Cannot specify `stream` and `loader` at the same time.\n */\n stream?: never;\n}\n\n/**\n * Options to the `resource` function, for creating a resource.\n *\n * @publicApi 22.0\n */\nexport interface StreamingResourceOptions<T, R> extends BaseResourceOptions<T, R> {\n /**\n * Loading function which returns a `Promise` of a signal of the resource's value for a given\n * request, which can change over time as new values are received from a stream.\n */\n stream: ResourceStreamingLoader<T, R>;\n\n /**\n * Cannot specify `stream` and `loader` at the same time.\n */\n loader?: never;\n}\n\n/**\n * @publicApi 22.0\n */\nexport type ResourceOptions<T, R> = (\n | PromiseResourceOptions<T, R>\n | StreamingResourceOptions<T, R>\n) & {\n /**\n * A debug name for the reactive node. Used in Angular DevTools to identify the node.\n */\n debugName?: string;\n};\n\n/**\n * @publicApi 22.0\n */\nexport type ResourceStreamItem<T> = {value: T} | {error: Error};\n\n/**\n * An explicit representation of a resource's state.\n *\n * @publicApi 22.0\n * @see [Resource composition with snapshots](guide/signals/resource#resource-composition-with-snapshots)\n */\nexport type ResourceSnapshot<T> =\n | {readonly status: 'idle'; readonly value: T}\n | {readonly status: 'loading' | 'reloading'; readonly value: T}\n | {readonly status: 'resolved' | 'local'; readonly value: T}\n | {readonly status: 'error'; readonly error: Error};\n\n/**\n * Options for `debounced`.\n *\n * @see [Debouncing signals with `debounced`](guide/signals/debounced)\n *\n * @experimental 22.0\n */\nexport interface DebouncedOptions<T> {\n /** The `Injector` to use for the debounced resource. */\n injector?: Injector;\n /** The equality function to use for comparing values. */\n equal?: ValueEqualityFn<T>;\n}\n\n/**\n * Represents the wait condition for item debouncing.\n * Can be a number of milliseconds or a function that returns a Promise.\n *\n * @see [Debouncing signals with `debounced`](guide/signals/debounced)\n *\n * @experimental 22.0\n */\nexport type DebounceTimer<T> =\n | number\n | ((value: T, lastValue: ResourceSnapshot<T>) => Promise<void> | void);\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ComputationFn,\n createLinkedSignal,\n LinkedSignalGetter,\n LinkedSignalNode,\n linkedSignalSetFn,\n linkedSignalUpdateFn,\n SIGNAL,\n} from '../../../primitives/signals';\nimport {Signal, ValueEqualityFn} from './api';\nimport {signalAsReadonlyFn, WritableSignal} from './signal';\n\nconst identityFn = <T>(v: T) => v;\n\n/**\n * Creates a writable signal whose value is initialized and reset by the linked, reactive computation.\n *\n * @publicApi 20.0\n */\nexport function linkedSignal<D>(\n computation: () => D,\n options?: {equal?: ValueEqualityFn<NoInfer<D>>; debugName?: string},\n): WritableSignal<D>;\n\n/**\n * Creates a writable signal whose value is initialized and reset by the linked, reactive computation.\n * This is an advanced API form where the computation has access to the previous value of the signal and the computation result.\n *\n * Note: The computation is reactive, meaning the linked signal will automatically update whenever any of the signals used within the computation change.\n *\n * @publicApi 20.0\n * @see [Dependent state with linkedSignal](guide/signals/linked-signal)\n */\nexport function linkedSignal<S, D>(options: {\n source: () => S;\n computation: (source: NoInfer<S>, previous?: {source: NoInfer<S>; value: NoInfer<D>}) => D;\n equal?: ValueEqualityFn<NoInfer<D>>;\n debugName?: string;\n}): WritableSignal<D>;\n\nexport function linkedSignal<S, D>(\n optionsOrComputation:\n | {\n source: () => S;\n computation: ComputationFn<S, D>;\n equal?: ValueEqualityFn<D>;\n debugName?: string;\n }\n | (() => D),\n options?: {equal?: ValueEqualityFn<D>; debugName?: string},\n): WritableSignal<D> {\n if (typeof optionsOrComputation === 'function') {\n const getter = createLinkedSignal<D, D>(\n optionsOrComputation,\n identityFn<D>,\n options?.equal,\n ) as LinkedSignalGetter<D, D> & WritableSignal<D>;\n return upgradeLinkedSignalGetter(getter, options?.debugName);\n } else {\n const getter = createLinkedSignal<S, D>(\n optionsOrComputation.source,\n optionsOrComputation.computation,\n optionsOrComputation.equal,\n );\n return upgradeLinkedSignalGetter(getter, optionsOrComputation.debugName);\n }\n}\n\nfunction upgradeLinkedSignalGetter<S, D>(\n getter: LinkedSignalGetter<S, D>,\n debugName?: string,\n): WritableSignal<D> {\n if (typeof ngDevMode !== 'undefined' && ngDevMode) {\n getter[SIGNAL].debugName = debugName;\n getter.toString = () => `[LinkedSignal${debugName ? ' (' + debugName + ')' : ''}: ${getter()}]`;\n }\n\n const node = getter[SIGNAL] as LinkedSignalNode<S, D>;\n const upgradedGetter = getter as LinkedSignalGetter<S, D> & WritableSignal<D>;\n\n upgradedGetter.set = (newValue: D) => linkedSignalSetFn(node, newValue);\n upgradedGetter.update = (updateFn: (value: D) => D) => linkedSignalUpdateFn(node, updateFn);\n upgradedGetter.asReadonly = signalAsReadonlyFn.bind(getter as any) as () => Signal<D>;\n\n return upgradedGetter;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {isSignal, Signal, ValueEqualityFn} from '../render3/reactivity/api';\nimport {computed} from '../render3/reactivity/computed';\nimport {effect, EffectRef} from '../render3/reactivity/effect';\nimport {signal, signalAsReadonlyFn, WritableSignal} from '../render3/reactivity/signal';\nimport {untracked} from '../render3/reactivity/untracked';\nimport {\n Resource,\n ResourceDependencyError,\n ResourceOptions,\n ResourceParamsStatus,\n ResourceSnapshot,\n ResourceStatus,\n ResourceStreamingLoader,\n ResourceStreamItem,\n StreamingResourceOptions,\n type ResourceParamsContext,\n type ResourceRef,\n type WritableResource,\n} from './api';\n\nimport {assertInInjectionContext} from '../di/contextual';\nimport {Injector} from '../di/injector';\nimport {inject} from '../di/injector_compatibility';\nimport {RuntimeError, RuntimeErrorCode} from '../errors';\nimport {CACHE_ACTIVE} from '../hydration/cache';\nimport {DestroyRef} from '../linker/destroy_ref';\nimport {PendingTasks} from '../pending_tasks';\nimport {linkedSignal} from '../render3/reactivity/linked_signal';\nimport {StateKey, TransferState} from '../transfer_state';\n\n/**\n * Constructs a `Resource` that projects a reactive request to an asynchronous operation defined by\n * a loader function, which exposes the result of the loading operation via signals.\n *\n * Note that `resource` is intended for _read_ operations, not operations which perform mutations.\n * `resource` will cancel in-progress loads via the `AbortSignal` when destroyed or when a new\n * request object becomes available, which could prematurely abort mutations.\n *\n * @see [Async reactivity with resources](guide/signals/resource)\n *\n * @publicApi 22.0\n */\nexport function resource<T, R>(\n options: ResourceOptions<T, R> & {defaultValue: NoInfer<T>},\n): ResourceRef<T>;\n\n/**\n * Constructs a `Resource` that projects a reactive request to an asynchronous operation defined by\n * a loader function, which exposes the result of the loading operation via signals.\n *\n * Note that `resource` is intended for _read_ operations, not operations which perform mutations.\n * `resource` will cancel in-progress loads via the `AbortSignal` when destroyed or when a new\n * request object becomes available, which could prematurely abort mutations.\n *\n * @publicApi 22.0\n * @see [Async reactivity with resources](guide/signals/resource)\n */\nexport function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined>;\nexport function resource<T, R>(options: ResourceOptions<T, R>): ResourceRef<T | undefined> {\n if (ngDevMode && !options?.injector) {\n assertInInjectionContext(resource);\n }\n\n const oldNameForParams = (\n options as ResourceOptions<T, R> & {request: ResourceOptions<T, R>['params']}\n ).request;\n const params = options.params ?? oldNameForParams ?? (() => null!);\n return new ResourceImpl<T | undefined, R>(\n params,\n getLoader(options),\n options.defaultValue,\n options.equal ? wrapEqualityFn(options.equal) : undefined,\n options.debugName,\n options.injector ?? inject(Injector),\n options.id as StateKey<T>,\n );\n}\n\ntype ResourceInternalStatus = 'idle' | 'loading' | 'resolved' | 'local';\n\n/**\n * Internal state of a resource.\n */\ninterface ResourceProtoState<T> {\n extRequest: WrappedRequest;\n\n // For simplicity, status is internally tracked as a subset of the public status enum.\n // Reloading and Error statuses are projected from Loading and Resolved based on other state.\n status: ResourceInternalStatus;\n}\n\ninterface ResourceState<T> extends ResourceProtoState<T> {\n previousStatus: ResourceStatus;\n stream: Signal<ResourceStreamItem<T>> | undefined;\n}\n\ntype WrappedRequest = {\n request?: unknown;\n reload: number;\n status?: ResourceInternalStatus;\n error?: Error;\n};\n\n/**\n * Base class which implements `.value` as a `WritableSignal` by delegating `.set` and `.update`.\n */\nabstract class BaseWritableResource<T> implements WritableResource<T> {\n readonly value: WritableSignal<T>;\n abstract readonly status: Signal<ResourceStatus>;\n abstract readonly error: Signal<Error | undefined>;\n\n abstract reload(): boolean;\n\n readonly isLoading: Signal<boolean>;\n\n constructor(value: Signal<T>, debugName: string | undefined) {\n this.value = value as WritableSignal<T>;\n this.value.set = this.set.bind(this);\n this.value.update = this.update.bind(this);\n this.value.asReadonly = signalAsReadonlyFn;\n\n this.isLoading = computed(\n () => this.status() === 'loading' || this.status() === 'reloading',\n ngDevMode ? createDebugNameObject(debugName, 'isLoading') : undefined,\n );\n }\n\n abstract set(value: T): void;\n\n private readonly isError = computed(() => this.status() === 'error');\n\n update(updateFn: (value: T) => T): void {\n this.set(updateFn(untracked(this.value)));\n }\n\n // Use a computed here to avoid triggering reactive consumers if the value changes while staying\n // either defined or undefined.\n private readonly isValueDefined = computed(() => {\n // Check if it's in an error state first to prevent the error from bubbling up.\n if (this.isError()) {\n return false;\n }\n\n return this.value() !== undefined;\n });\n\n private _snapshot: Signal<ResourceSnapshot<T>> | undefined;\n get snapshot(): Signal<ResourceSnapshot<T>> {\n return (this._snapshot ??= computed(() => {\n const status = this.status();\n if (status === 'error') {\n return {status: 'error', error: this.error()!};\n } else {\n return {status, value: this.value()};\n }\n }));\n }\n\n hasValue(): this is ResourceRef<Exclude<T, undefined>> {\n return this.isValueDefined();\n }\n\n asReadonly(): Resource<T> {\n return this;\n }\n}\n\n/**\n * Implementation for `resource()` which uses a `linkedSignal` to manage the resource's state.\n */\nexport class ResourceImpl<T, R> extends BaseWritableResource<T> implements ResourceRef<T> {\n private readonly pendingTasks: PendingTasks;\n\n /**\n * The current state of the resource. Status, value, and error are derived from this.\n */\n private readonly state: WritableSignal<ResourceState<T>>;\n\n /**\n * Combines the current request with a reload counter which allows the resource to be reloaded on\n * imperative command.\n */\n protected readonly extRequest: WritableSignal<WrappedRequest>;\n private readonly effectRef: EffectRef;\n\n private pendingController: AbortController | undefined;\n private resolvePendingTask: (() => void) | undefined = undefined;\n private destroyed = false;\n private unregisterOnDestroy: () => void;\n\n override readonly status: Signal<ResourceStatus>;\n override readonly error: Signal<Error | undefined>;\n private readonly transferState: TransferState | undefined;\n\n constructor(\n request: (ctx: ResourceParamsContext) => R,\n private readonly loaderFn: ResourceStreamingLoader<T, R>,\n defaultValue: T,\n private readonly equal: ValueEqualityFn<T> | undefined,\n private readonly debugName: string | undefined,\n injector: Injector,\n private transferCacheKey: StateKey<T> | undefined,\n getInitialStream?: (request: R) => Signal<ResourceStreamItem<T>> | undefined,\n ) {\n if (isInParamsFunction()) {\n throw invalidResourceCreationInParams();\n }\n\n super(\n // Feed a computed signal for the value to `BaseWritableResource`, which will upgrade it to a\n // `WritableSignal` that delegates to `ResourceImpl.set`.\n computed(\n () => {\n const streamValue = this.state().stream?.();\n\n if (!streamValue) {\n return defaultValue;\n }\n\n // Prevents `hasValue()` from throwing an error when a reload happened in the error state\n if (this.state().status === 'loading' && this.error()) {\n return defaultValue;\n }\n\n if (!isResolved(streamValue)) {\n throw new ResourceValueError(this.error()!);\n }\n\n return streamValue.value;\n },\n {equal, ...(ngDevMode ? createDebugNameObject(debugName, 'value') : undefined)},\n ),\n debugName,\n );\n\n const cacheState = injector.get(CACHE_ACTIVE, undefined, {optional: true}) ?? {isActive: false};\n\n this.transferState = injector.get(TransferState, undefined, {optional: true}) ?? undefined;\n\n this.extRequest = linkedSignal<WrappedRequest>(\n () => {\n try {\n setInParamsFunction(true);\n return {request: request(paramsContext), reload: 0};\n } catch (error) {\n rethrowFatalErrors(error);\n if (error === ResourceParamsStatus.IDLE) {\n return {status: 'idle', reload: 0};\n } else if (error === ResourceParamsStatus.LOADING) {\n return {status: 'loading', reload: 0};\n }\n return {error: error as Error, reload: 0};\n } finally {\n setInParamsFunction(false);\n }\n },\n ngDevMode ? createDebugNameObject(debugName, 'extRequest') : undefined,\n );\n\n // The main resource state is managed in a `linkedSignal`, which allows the resource to change\n // state instantaneously when the request signal changes.\n this.state = linkedSignal<WrappedRequest, ResourceState<T>>({\n // Whenever the request changes,\n source: this.extRequest,\n // Compute the state of the resource given a change in status.\n computation: (extRequest, previous) => {\n let {request, status, error} = extRequest;\n let stream: Signal<ResourceStreamItem<T>> | undefined;\n\n if (error) {\n status = 'resolved';\n stream = signal(\n {error: encapsulateResourceError(error)},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n );\n } else if (!status) {\n if (!previous) {\n const transferState = this.transferState;\n const cacheKey = this.transferCacheKey;\n if (cacheState.isActive && cacheKey && transferState && request !== undefined) {\n const key = this.transferCacheKey;\n if (transferState.hasKey(cacheKey)) {\n stream = signal(\n {value: transferState.get(cacheKey, defaultValue)},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n );\n }\n }\n\n if (!stream) {\n stream = getInitialStream?.(extRequest.request as R);\n }\n // Clear getInitialStream so it doesn't hold onto memory\n getInitialStream = undefined;\n status = request === undefined ? 'idle' : stream ? 'resolved' : 'loading';\n } else {\n status = request === undefined ? 'idle' : 'loading';\n if (previous.value.extRequest.request === request) {\n stream = previous.value.stream;\n }\n }\n }\n\n return {\n extRequest,\n status,\n previousStatus: previous ? projectStatusOfState(previous.value) : 'idle',\n stream,\n };\n },\n ...(ngDevMode ? createDebugNameObject(debugName, 'state') : undefined),\n });\n\n this.effectRef = effect(this.loadEffect.bind(this), {\n injector,\n manualCleanup: true,\n ...(ngDevMode ? createDebugNameObject(debugName, 'loadEffect') : undefined),\n });\n\n this.pendingTasks = injector.get(PendingTasks);\n\n // Cancel any pending request when the resource itself is destroyed.\n this.unregisterOnDestroy = injector.get(DestroyRef).onDestroy(() => this.destroy());\n\n this.status = computed(\n () => projectStatusOfState(this.state()),\n ngDevMode ? createDebugNameObject(debugName, 'status') : undefined,\n );\n\n this.error = computed(\n () => {\n const stream = this.state().stream?.();\n return stream && !isResolved(stream) ? stream.error : undefined;\n },\n ngDevMode ? createDebugNameObject(debugName, 'error') : undefined,\n );\n }\n\n /**\n * Called either directly via `WritableResource.set` or via `.value.set()`.\n */\n override set(value: T): void {\n if (this.destroyed) {\n return;\n }\n\n const error = untracked(this.error);\n const state = untracked(this.state);\n\n if (!error) {\n const current = untracked(this.value);\n if (\n state.status === 'local' &&\n (this.equal ? this.equal(current, value) : current === value)\n ) {\n return;\n }\n }\n\n // Enter Local state with the user-defined value.\n this.state.set({\n extRequest: state.extRequest,\n status: 'local',\n previousStatus: 'local',\n stream: signal(\n {value},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n ),\n });\n\n // We're departing from whatever state the resource was in previously, so cancel any in-progress\n // loading operations.\n this.abortInProgressLoad();\n }\n\n override reload(): boolean {\n // We don't want to restart in-progress loads.\n const {status} = untracked(this.state);\n if (status === 'idle' || status === 'loading') {\n return false;\n }\n\n // Increment the request reload to trigger the `state` linked signal to switch us to `Reload`\n this.extRequest.update(({request, reload}) => ({request, reload: reload + 1}));\n return true;\n }\n\n destroy(): void {\n this.destroyed = true;\n this.unregisterOnDestroy();\n this.effectRef.destroy();\n this.abortInProgressLoad();\n\n // Destroyed resources enter Idle state.\n this.state.set({\n extRequest: {request: undefined, reload: 0},\n status: 'idle',\n previousStatus: 'idle',\n stream: undefined,\n });\n }\n\n private async loadEffect(): Promise<void> {\n const extRequest = this.extRequest();\n\n // Capture the previous status before any state transitions. Note that this is `untracked` since\n // we do not want the effect to depend on the state of the resource, only on the request.\n const {status: currentStatus, previousStatus} = untracked(this.state);\n\n if (extRequest.request === undefined) {\n // Nothing to load (and we should already be in a non-loading state).\n return;\n } else if (currentStatus !== 'loading') {\n // We're not in a loading or reloading state, so this loading request is stale.\n return;\n }\n\n // Cancel any previous loading attempts.\n this.abortInProgressLoad();\n\n // Capturing _this_ load's pending task in a local variable is important here. We may attempt to\n // resolve it twice:\n //\n // 1. when the loading function promise resolves/rejects\n // 2. when cancelling the loading operation\n //\n // After the loading operation is cancelled, `this.resolvePendingTask` no longer represents this\n // particular task, but this `await` may eventually resolve/reject. Thus, when we cancel in\n // response to (1) below, we need to cancel the locally saved task.\n let resolvePendingTask: (() => void) | undefined = (this.resolvePendingTask =\n this.pendingTasks.add());\n\n const {signal: abortSignal} = (this.pendingController = new AbortController());\n\n try {\n // The actual loading is run through `untracked` - only the request side of `resource` is\n // reactive. This avoids any confusion with signals tracking or not tracking depending on\n // which side of the `await` they are.\n const stream = untracked(() => {\n return this.loaderFn({\n params: extRequest.request as Exclude<R, undefined>,\n abortSignal,\n previous: {\n status: previousStatus,\n },\n });\n });\n\n // If this request has been aborted, or the current request no longer\n // matches this load, then we should ignore this resolution.\n const shouldDiscard = () => abortSignal.aborted || untracked(this.extRequest) !== extRequest;\n\n if (isSignal(stream)) {\n if (shouldDiscard()) {\n return;\n }\n\n this.state.set({\n extRequest,\n status: 'resolved',\n previousStatus: 'resolved',\n stream,\n });\n\n const result = untracked(stream);\n if (typeof ngServerMode !== 'undefined' && ngServerMode) {\n saveToTransferState(result, this.transferCacheKey, this.transferState);\n }\n } else {\n const resolvedStream = await stream;\n if (shouldDiscard()) {\n return;\n }\n\n this.state.set({\n extRequest,\n status: 'resolved',\n previousStatus: 'resolved',\n stream: resolvedStream,\n });\n\n // Use a local variable for the result so TypeScript can narrow `resolvedStream` correctly.\n const result = resolvedStream ? untracked(resolvedStream) : undefined;\n if (typeof ngServerMode !== 'undefined' && ngServerMode) {\n saveToTransferState(result, this.transferCacheKey, this.transferState);\n }\n }\n } catch (err) {\n rethrowFatalErrors(err);\n if (abortSignal.aborted || untracked(this.extRequest) !== extRequest) {\n return;\n }\n\n this.state.set({\n extRequest,\n status: 'resolved',\n previousStatus: 'error',\n stream: signal(\n {error: encapsulateResourceError(err)},\n ngDevMode ? createDebugNameObject(this.debugName, 'stream') : undefined,\n ),\n });\n } finally {\n // Resolve the pending task now that the resource has a value.\n resolvePendingTask?.();\n resolvePendingTask = undefined;\n }\n }\n\n private abortInProgressLoad(): void {\n untracked(() => this.pendingController?.abort());\n this.pendingController = undefined;\n\n // Once the load is aborted, we no longer want to block stability on its resolution.\n this.resolvePendingTask?.();\n this.resolvePendingTask = undefined;\n }\n}\n\nfunction saveToTransferState<R, T>(\n result: ResourceStreamItem<T> | undefined,\n transferCacheKey: StateKey<T> | undefined,\n transferState: TransferState | undefined,\n): void {\n if (transferCacheKey && transferState && result && isResolved(result)) {\n transferState.set(transferCacheKey, result.value);\n }\n}\n\n/**\n * Wraps an equality function to handle either value being `undefined`.\n */\nfunction wrapEqualityFn<T>(equal: ValueEqualityFn<T>): ValueEqualityFn<T | undefined> {\n return (a, b) => (a === undefined || b === undefined ? a === b : equal(a, b));\n}\n\nfunction getLoader<T, R>(options: ResourceOptions<T, R>): ResourceStreamingLoader<T, R> {\n if (isStreamingResourceOptions(options)) {\n return options.stream;\n }\n\n return async (params) => {\n try {\n return signal(\n {value: await options.loader(params)},\n ngDevMode ? createDebugNameObject(options.debugName, 'stream') : undefined,\n );\n } catch (err) {\n return signal(\n {error: encapsulateResourceError(err)},\n ngDevMode ? createDebugNameObject(options.debugName, 'stream') : undefined,\n );\n }\n };\n}\n\nfunction isStreamingResourceOptions<T, R>(\n options: ResourceOptions<T, R>,\n): options is StreamingResourceOptions<T, R> {\n return !!(options as StreamingResourceOptions<T, R>).stream;\n}\n\n/**\n * Project from a state with `ResourceInternalStatus` to the user-facing `ResourceStatus`\n */\nfunction projectStatusOfState(state: ResourceState<unknown>): ResourceStatus {\n switch (state.status) {\n case 'loading':\n return state.extRequest.reload === 0 ? 'loading' : 'reloading';\n case 'resolved':\n return isResolved(state.stream!()) ? 'resolved' : 'error';\n default:\n return state.status;\n }\n}\n\nfunction isResolved<T>(state: ResourceStreamItem<T>): state is {value: T} {\n return (state as {error: unknown}).error === undefined;\n}\n\n/**\n * Creates a debug name object for an internal signal.\n */\nfunction createDebugNameObject(\n resourceDebugName: string | undefined,\n internalSignalDebugName: string,\n): {debugName?: string} {\n return {\n debugName: `Resource${resourceDebugName ? '#' + resourceDebugName : ''}.${internalSignalDebugName}`,\n };\n}\n\nexport function encapsulateResourceError(error: unknown): Error {\n if (isErrorLike(error)) {\n return error;\n }\n\n return new ResourceWrappedError(error);\n}\n\nexport function isErrorLike(error: unknown): error is Error {\n return (\n error instanceof Error ||\n (typeof error === 'object' &&\n typeof (error as Error).name === 'string' &&\n typeof (error as Error).message === 'string')\n );\n}\n\nexport class ResourceValueError extends Error {\n constructor(error: Error) {\n super(\n ngDevMode\n ? `Resource is currently in an error state (see Error.cause for details): ${error.message}`\n : error.message,\n {cause: error},\n );\n }\n}\n\nclass ResourceWrappedError extends Error {\n constructor(error: unknown) {\n super(\n ngDevMode\n ? `Resource returned an error that's not an Error instance: ${String(error)}. Check this error's .cause for the actual error.`\n : String(error),\n {cause: error},\n );\n }\n}\n\n/**\n * Chains the value of another resource into the params of the current resource, returning the value\n * of the other resource if it is available, or propagating the status to the current resource if it\n * is not.\n */\nexport function chain<T>(resource: Resource<T>): T {\n switch (resource.status()) {\n case 'idle':\n throw ResourceParamsStatus.IDLE;\n case 'error':\n throw new ResourceDependencyError(resource);\n case 'loading':\n case 'reloading':\n throw ResourceParamsStatus.LOADING;\n }\n return resource.value();\n}\n\nexport const paramsContext: ResourceParamsContext = {\n chain,\n};\n\nlet inParamsFunction = false;\n\nexport function isInParamsFunction() {\n return inParamsFunction;\n}\n\nexport function setInParamsFunction(value: boolean) {\n inParamsFunction = value;\n}\n\nexport function invalidResourceCreationInParams(): Error {\n return new RuntimeError(\n RuntimeErrorCode.INVALID_RESOURCE_CREATION_IN_PARAMS,\n ngDevMode && `Cannot create a resource inside the \\`params\\` of another resource`,\n );\n}\n\nexport function rethrowFatalErrors(error: unknown) {\n if (\n error instanceof RuntimeError &&\n error.code === RuntimeErrorCode.INVALID_RESOURCE_CREATION_IN_PARAMS\n ) {\n throw error;\n }\n}\n"],"names":["OutputEmitterRef","destroyed","listeners","errorHandler","inject","ErrorHandler","optional","destroyRef","DestroyRef","constructor","onDestroy","subscribe","callback","RuntimeError","ngDevMode","push","unsubscribe","idx","indexOf","undefined","splice","emit","value","console","warn","formatRuntimeError","previousConsumer","setActiveConsumer","listenerFn","err","handleError","getOutputDestroyRef","ref","CACHE_ACTIVE","InjectionToken","computed","computation","options","getter","createComputed","equal","debugName","SIGNAL","toString","untracked","nonReactiveReadsFn","untrackedPrimitive","ResourceDependencyError","Error","dependency","cause","error","name","ResourceParamsStatus","_brand","msg","IDLE","LOADING","identityFn","v","linkedSignal","optionsOrComputation","createLinkedSignal","upgradeLinkedSignalGetter","source","node","upgradedGetter","set","newValue","linkedSignalSetFn","update","updateFn","linkedSignalUpdateFn","asReadonly","signalAsReadonlyFn","bind","resource","injector","assertInInjectionContext","oldNameForParams","request","params","ResourceImpl","getLoader","defaultValue","wrapEqualityFn","Injector","id","BaseWritableResource","isLoading","status","createDebugNameObject","isError","isValueDefined","_snapshot","snapshot","hasValue","loaderFn","transferCacheKey","pendingTasks","state","extRequest","effectRef","pendingController","resolvePendingTask","unregisterOnDestroy","transferState","getInitialStream","isInParamsFunction","invalidResourceCreationInParams","streamValue","stream","isResolved","ResourceValueError","cacheState","get","isActive","TransferState","setInParamsFunction","paramsContext","reload","rethrowFatalErrors","previous","signal","encapsulateResourceError","cacheKey","hasKey","previousStatus","projectStatusOfState","effect","loadEffect","manualCleanup","PendingTasks","destroy","current","abortInProgressLoad","currentStatus","add","abortSignal","AbortController","shouldDiscard","aborted","isSignal","result","ngServerMode","saveToTransferState","resolvedStream","abort","a","b","isStreamingResourceOptions","loader","resourceDebugName","internalSignalDebugName","isErrorLike","ResourceWrappedError","message","String","chain","inParamsFunction","code"],"mappings":"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"}
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

{
"name": "@angular/core",
"version": "22.0.0-next.12",
"version": "22.0.0-rc.0",
"description": "Angular - the core framework",

@@ -53,3 +53,3 @@ "author": "angular",

"peerDependencies": {
"@angular/compiler": "22.0.0-next.12",
"@angular/compiler": "22.0.0-rc.0",
"rxjs": "^6.5.3 || ^7.4.0",

@@ -56,0 +56,0 @@ "zone.js": "~0.15.0 || ~0.16.0"

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -16,3 +16,3 @@ * License: MIT

var apply_import_manager = require('./apply_import_manager-CxA_YYgB.cjs');
var index = require('./index-DcezkXLN.cjs');
var index = require('./index-DxFMpcXS.cjs');
require('@angular-devkit/core');

@@ -19,0 +19,0 @@ require('node:path/posix');

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -522,3 +522,3 @@ * License: MIT

block.expression.visit(this.exprMigrator, false);
block.trackBy.visit(this.exprMigrator, false);
block.trackBy?.visit(this.exprMigrator, false);
super.visitForLoopBlock(block);

@@ -525,0 +525,0 @@ }

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -15,5 +15,5 @@ * License: MIT

var apply_import_manager = require('./apply_import_manager-CxA_YYgB.cjs');
var migrate_ts_type_references = require('./migrate_ts_type_references-xRTTASnu.cjs');
var migrate_ts_type_references = require('./migrate_ts_type_references-DMv-GSuu.cjs');
var assert = require('assert');
var index = require('./index-DcezkXLN.cjs');
var index = require('./index-DxFMpcXS.cjs');
var compiler = require('@angular/compiler');

@@ -20,0 +20,0 @@ require('@angular-devkit/core');

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -22,5 +22,5 @@ * License: MIT

require('./apply_import_manager-CxA_YYgB.cjs');
require('./migrate_ts_type_references-xRTTASnu.cjs');
require('./migrate_ts_type_references-DMv-GSuu.cjs');
require('assert');
require('./index-DcezkXLN.cjs');
require('./index-DxFMpcXS.cjs');
require('@angular/compiler');

@@ -27,0 +27,0 @@ require('./leading_space-BTPRV0wu.cjs');

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -5,0 +5,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

/**
* @license Angular v22.0.0-next.12
* @license Angular v22.0.0-rc.0
* (c) 2010-2026 Google LLC. https://angular.dev/

@@ -4,0 +4,0 @@ * License: MIT

'use strict';
/**
* @license Angular v22.0.0-next.12
* (c) 2010-2026 Google LLC. https://angular.dev/
* License: MIT
*/
'use strict';
var ts = require('typescript');
var compilerCli = require('@angular/compiler-cli');
var migrations = require('@angular/compiler-cli/private/migrations');
require('node:path');
var project_paths = require('./project_paths-D2V-Uh2L.cjs');
var compiler = require('@angular/compiler');
function getMemberName(member) {
if (member.name === undefined) {
return null;
}
if (ts.isIdentifier(member.name) || ts.isStringLiteralLike(member.name)) {
return member.name.text;
}
if (ts.isPrivateIdentifier(member.name)) {
return `#${member.name.text}`;
}
return null;
}
/** Checks whether the given node can be an `@Input()` declaration node. */
function isInputContainerNode(node) {
return (((ts.isAccessor(node) && ts.isClassDeclaration(node.parent)) ||
ts.isPropertyDeclaration(node)) &&
getMemberName(node) !== null);
}
/**
* Detects `query(By.directive(T)).componentInstance` patterns and enhances
* them with information of `T`. This is important because `.componentInstance`
* is currently typed as `any` and may cause runtime test failures after input
* migrations then.
*
* The reference resolution pass leverages information from this pattern
* recognizer.
*/
class DebugElementComponentInstance {
checker;
cache = new WeakMap();
constructor(checker) {
this.checker = checker;
}
detect(node) {
if (this.cache.has(node)) {
return this.cache.get(node);
}
if (!ts.isPropertyAccessExpression(node)) {
return null;
}
// Check for `<>.componentInstance`.
if (!ts.isIdentifier(node.name) || node.name.text !== 'componentInstance') {
return null;
}
// Check for `<>.query(..).<>`.
if (!ts.isCallExpression(node.expression) ||
!ts.isPropertyAccessExpression(node.expression.expression) ||
!ts.isIdentifier(node.expression.expression.name) ||
node.expression.expression.name.text !== 'query') {
return null;
}
const queryCall = node.expression;
if (queryCall.arguments.length !== 1) {
return null;
}
const queryArg = queryCall.arguments[0];
let typeExpr;
if (ts.isCallExpression(queryArg) &&
queryArg.arguments.length === 1 &&
ts.isIdentifier(queryArg.arguments[0])) {
// Detect references, like: `query(By.directive(T))`.
typeExpr = queryArg.arguments[0];
}
else if (ts.isIdentifier(queryArg)) {
// Detect references, like: `harness.query(T)`.
typeExpr = queryArg;
}
else {
return null;
}
const symbol = this.checker.getSymbolAtLocation(typeExpr);
if (symbol?.valueDeclaration === undefined ||
!ts.isClassDeclaration(symbol?.valueDeclaration)) {
// Cache this as we use the expensive type checker.
this.cache.set(node, null);
return null;
}
const type = this.checker.getTypeAtLocation(symbol.valueDeclaration);
this.cache.set(node, type);
return type;
}
}
/**
* Recognizes `Partial<T>` instances in Catalyst tests. Those type queries
* are likely used for typing property initialization values for the given class `T`
* and we have a few scenarios:
*
* 1. The API does not unwrap signal inputs. In which case, the values are likely no
* longer assignable to an `InputSignal`.
* 2. The API does unwrap signal inputs, in which case we need to unwrap the `Partial`
* because the values are raw initial values, like they were before.
*
* We can enable this heuristic when we detect Catalyst as we know it supports unwrapping.
*/
class PartialDirectiveTypeInCatalystTests {
checker;
knownFields;
constructor(checker, knownFields) {
this.checker = checker;
this.knownFields = knownFields;
}
detect(node) {
// Detect `Partial<...>`
if (!ts.isTypeReferenceNode(node) ||
!ts.isIdentifier(node.typeName) ||
node.typeName.text !== 'Partial') {
return null;
}
// Ignore if the source file doesn't reference Catalyst.
if (!node.getSourceFile().text.includes('angular2/testing/catalyst')) {
return null;
}
// Extract T of `Partial<T>`.
const cmpTypeArg = node.typeArguments?.[0];
if (!cmpTypeArg ||
!ts.isTypeReferenceNode(cmpTypeArg) ||
!ts.isIdentifier(cmpTypeArg.typeName)) {
return null;
}
const cmpType = cmpTypeArg.typeName;
const symbol = this.checker.getSymbolAtLocation(cmpType);
// Note: Technically the class might be derived of an input-containing class,
// but this is out of scope for now. We can expand if we see it's a common case.
if (symbol?.valueDeclaration === undefined ||
!ts.isClassDeclaration(symbol.valueDeclaration) ||
!this.knownFields.shouldTrackClassReference(symbol.valueDeclaration)) {
return null;
}
return { referenceNode: node, targetClass: symbol.valueDeclaration };
}
}
/**
* Attempts to look up the given property access chain using
* the type checker.
*
* Notably this is not as safe as using the type checker directly to
* retrieve symbols of a given identifier, but in some cases this is
* a necessary approach to compensate e.g. for a lack of TCB information
* when processing Angular templates.
*
* The path is a list of properties to be accessed sequentially on the
* given type.
*/
function lookupPropertyAccess(checker, type, path, options = {}) {
let symbol = null;
for (const propName of path) {
// Note: We support assuming `NonNullable` for the pathl This is necessary
// in some situations as otherwise the lookups would fail to resolve the target
// symbol just because of e.g. a ternary. This is used in the signal input migration
// for host bindings.
type = options.ignoreNullability ? type.getNonNullableType() : type;
const propSymbol = type.getProperty(propName);
if (propSymbol === undefined) {
return null;
}
symbol = propSymbol;
type = checker.getTypeOfSymbol(propSymbol);
}
if (symbol === null) {
return null;
}
return { symbol, type };
}
/**
* AST visitor that iterates through a template and finds all
* input references.
*
* This resolution is important to be able to migrate references to inputs
* that will be migrated to signal inputs.
*/
class TemplateReferenceVisitor extends compiler.TmplAstRecursiveVisitor {
result = [];
/**
* Whether we are currently descending into HTML AST nodes
* where all bound attributes are considered potentially narrowing.
*
* Keeps track of all referenced inputs in such attribute expressions.
*/
templateAttributeReferencedFields = null;
expressionVisitor;
seenKnownFieldsCount = new Map();
constructor(typeChecker, templateTypeChecker, componentClass, knownFields, fieldNamesToConsiderForReferenceLookup) {
super();
this.expressionVisitor = new TemplateExpressionReferenceVisitor(typeChecker, templateTypeChecker, componentClass, knownFields, fieldNamesToConsiderForReferenceLookup);
}
checkExpressionForReferencedFields(activeNode, expressionNode) {
const referencedFields = this.expressionVisitor.checkTemplateExpression(activeNode, expressionNode);
// Add all references to the overall visitor result.
this.result.push(...referencedFields);
// Count usages of seen input references. We'll use this to make decisions
// based on whether inputs are potentially narrowed or not.
for (const input of referencedFields) {
this.seenKnownFieldsCount.set(input.targetField.key, (this.seenKnownFieldsCount.get(input.targetField.key) ?? 0) + 1);
}
return referencedFields;
}
descendAndCheckForNarrowedSimilarReferences(potentiallyNarrowedInputs, descend) {
const inputs = potentiallyNarrowedInputs.map((i) => ({
ref: i,
key: i.targetField.key,
pastCount: this.seenKnownFieldsCount.get(i.targetField.key) ?? 0,
}));
descend();
for (const input of inputs) {
// Input was referenced inside a narrowable spot, and is used in child nodes.
// This is a sign for the input to be narrowed. Mark it as such.
if ((this.seenKnownFieldsCount.get(input.key) ?? 0) > input.pastCount) {
input.ref.isLikelyNarrowed = true;
}
}
}
visitTemplate(template) {
// Note: We assume all bound expressions for templates may be subject
// to TCB narrowing. This is relevant for now until we support narrowing
// of signal calls in templates.
// TODO: Remove with: https://github.com/angular/angular/pull/55456.
this.templateAttributeReferencedFields = [];
compiler.tmplAstVisitAll(this, template.attributes);
compiler.tmplAstVisitAll(this, template.templateAttrs);
// If we are dealing with a microsyntax template, do not check
// inputs and outputs as those are already passed to the children.
// Template attributes may contain relevant expressions though.
if (template.tagName === 'ng-template') {
compiler.tmplAstVisitAll(this, template.inputs);
compiler.tmplAstVisitAll(this, template.outputs);
}
const referencedInputs = this.templateAttributeReferencedFields;
this.templateAttributeReferencedFields = null;
this.descendAndCheckForNarrowedSimilarReferences(referencedInputs, () => {
compiler.tmplAstVisitAll(this, template.children);
compiler.tmplAstVisitAll(this, template.references);
compiler.tmplAstVisitAll(this, template.variables);
});
}
visitIfBlockBranch(block) {
if (block.expression) {
const referencedFields = this.checkExpressionForReferencedFields(block, block.expression);
this.descendAndCheckForNarrowedSimilarReferences(referencedFields, () => {
super.visitIfBlockBranch(block);
});
}
else {
super.visitIfBlockBranch(block);
}
}
visitForLoopBlock(block) {
this.checkExpressionForReferencedFields(block, block.expression);
this.checkExpressionForReferencedFields(block, block.trackBy);
super.visitForLoopBlock(block);
}
visitSwitchBlock(block) {
const referencedFields = this.checkExpressionForReferencedFields(block, block.expression);
this.descendAndCheckForNarrowedSimilarReferences(referencedFields, () => {
super.visitSwitchBlock(block);
});
}
visitSwitchBlockCase(block) {
if (block.expression) {
const referencedFields = this.checkExpressionForReferencedFields(block, block.expression);
this.descendAndCheckForNarrowedSimilarReferences(referencedFields, () => {
super.visitSwitchBlockCase(block);
});
}
else {
super.visitSwitchBlockCase(block);
}
}
visitDeferredBlock(deferred) {
if (deferred.triggers.when) {
this.checkExpressionForReferencedFields(deferred, deferred.triggers.when.value);
}
if (deferred.prefetchTriggers.when) {
this.checkExpressionForReferencedFields(deferred, deferred.prefetchTriggers.when.value);
}
super.visitDeferredBlock(deferred);
}
visitBoundText(text) {
this.checkExpressionForReferencedFields(text, text.value);
}
visitBoundEvent(attribute) {
this.checkExpressionForReferencedFields(attribute, attribute.handler);
}
visitBoundAttribute(attribute) {
const referencedFields = this.checkExpressionForReferencedFields(attribute, attribute.value);
// Attributes inside templates are potentially "narrowed" and hence we
// keep track of all referenced inputs to see if they actually are.
if (this.templateAttributeReferencedFields !== null) {
this.templateAttributeReferencedFields.push(...referencedFields);
}
}
visitLetDeclaration(decl) {
this.checkExpressionForReferencedFields(decl, decl.value);
}
}
/**
* Expression AST visitor that checks whether a given expression references
* a known `@Input()`.
*
* This resolution is important to be able to migrate references to inputs
* that will be migrated to signal inputs.
*/
class TemplateExpressionReferenceVisitor extends compiler.RecursiveAstVisitor {
typeChecker;
templateTypeChecker;
componentClass;
knownFields;
fieldNamesToConsiderForReferenceLookup;
activeTmplAstNode = null;
detectedInputReferences = [];
isInsideObjectShorthandExpression = false;
insideConditionalExpressionsWithReads = [];
constructor(typeChecker, templateTypeChecker, componentClass, knownFields, fieldNamesToConsiderForReferenceLookup) {
super();
this.typeChecker = typeChecker;
this.templateTypeChecker = templateTypeChecker;
this.componentClass = componentClass;
this.knownFields = knownFields;
this.fieldNamesToConsiderForReferenceLookup = fieldNamesToConsiderForReferenceLookup;
}
/** Checks the given AST expression. */
checkTemplateExpression(activeNode, expressionNode) {
this.detectedInputReferences = [];
this.activeTmplAstNode = activeNode;
expressionNode.visit(this, []);
return this.detectedInputReferences;
}
visit(ast, context) {
super.visit(ast, [...context, ast]);
}
// Keep track when we are inside an object shorthand expression. This is
// necessary as we need to expand the shorthand to invoke a potential new signal.
// E.g. `{bla}` may be transformed to `{bla: bla()}`.
visitLiteralMap(ast, context) {
for (const [idx, key] of ast.keys.entries()) {
this.isInsideObjectShorthandExpression =
key.kind === 'property' && !!key.isShorthandInitialized;
ast.values[idx].visit(this, context);
this.isInsideObjectShorthandExpression = false;
}
}
visitPropertyRead(ast, context) {
this._inspectPropertyAccess(ast, false, context);
super.visitPropertyRead(ast, context);
}
visitSafePropertyRead(ast, context) {
this._inspectPropertyAccess(ast, false, context);
super.visitPropertyRead(ast, context);
}
visitBinary(ast, context) {
if (ast.operation === '=' && ast.left instanceof compiler.PropertyRead) {
this._inspectPropertyAccess(ast.left, true, [...context, ast, ast.left]);
}
else {
super.visitBinary(ast, context);
}
}
visitConditional(ast, context) {
this.visit(ast.condition, context);
this.insideConditionalExpressionsWithReads.push(ast.condition);
this.visit(ast.trueExp, context);
this.visit(ast.falseExp, context);
this.insideConditionalExpressionsWithReads.pop();
}
/**
* Inspects the property access and attempts to resolve whether they access
* a known field. If so, the result is captured.
*/
_inspectPropertyAccess(ast, isAssignment, astPath) {
if (this.fieldNamesToConsiderForReferenceLookup !== null &&
!this.fieldNamesToConsiderForReferenceLookup.has(ast.name)) {
return;
}
const isWrite = !!(isAssignment ||
(this.activeTmplAstNode && isTwoWayBindingNode(this.activeTmplAstNode)));
this._checkAccessViaTemplateTypeCheckBlock(ast, isWrite, astPath) ||
this._checkAccessViaOwningComponentClassType(ast, isWrite, astPath);
}
/**
* Checks whether the node refers to an input using the TCB information.
* Type check block may not exist for e.g. test components, so this can return `null`.
*/
_checkAccessViaTemplateTypeCheckBlock(ast, isWrite, astPath) {
// There might be no template type checker. E.g. if we check host bindings.
if (this.templateTypeChecker === null) {
return false;
}
const symbol = this.templateTypeChecker.getSymbolOfNode(ast, this.componentClass);
if (symbol?.kind !== migrations.SymbolKind.Expression) {
return false;
}
const tsSymbol = this.templateTypeChecker.getTsSymbolOfSymbol(symbol);
if (tsSymbol === null) {
return false;
}
// Dangerous: Type checking symbol retrieval is a totally different `ts.Program`,
// than the one where we analyzed `knownInputs`.
// --> Find the input via its input id.
const targetInput = this.knownFields.attemptRetrieveDescriptorFromSymbol(tsSymbol);
if (targetInput === null) {
return false;
}
this.detectedInputReferences.push({
targetNode: targetInput.node,
targetField: targetInput,
read: ast,
readAstPath: astPath,
context: this.activeTmplAstNode,
isLikelyNarrowed: this._isPartOfNarrowingTernary(ast),
isObjectShorthandExpression: this.isInsideObjectShorthandExpression,
isWrite,
});
return true;
}
/**
* Simple resolution checking whether the given AST refers to a known input.
* This is a fallback for when there is no type checking information (e.g. in host bindings).
*
* It attempts to resolve references by traversing accesses of the "component class" type.
* e.g. `this.bla` is resolved via `CompType#bla` and further.
*/
_checkAccessViaOwningComponentClassType(ast, isWrite, astPath) {
// We might check host bindings, which can never point to template variables or local refs.
const expressionTemplateTarget = this.templateTypeChecker === null
? null
: this.templateTypeChecker.getExpressionTarget(ast, this.componentClass);
// Skip checking if:
// - the reference resolves to a template variable or local ref. No way to resolve without TCB.
// - the owning component does not have a name (should not happen technically).
if (expressionTemplateTarget !== null || this.componentClass.name === undefined) {
return;
}
const property = traverseReceiverAndLookupSymbol(ast, this.componentClass, this.typeChecker);
if (property === null) {
return;
}
const matchingTarget = this.knownFields.attemptRetrieveDescriptorFromSymbol(property);
if (matchingTarget === null) {
return;
}
this.detectedInputReferences.push({
targetNode: matchingTarget.node,
targetField: matchingTarget,
read: ast,
readAstPath: astPath,
context: this.activeTmplAstNode,
isLikelyNarrowed: this._isPartOfNarrowingTernary(ast),
isObjectShorthandExpression: this.isInsideObjectShorthandExpression,
isWrite,
});
}
_isPartOfNarrowingTernary(read) {
// Note: We do not safe check that the reads are fully matching 1:1. This is acceptable
// as worst case we just skip an input from being migrated. This is very unlikely too.
return this.insideConditionalExpressionsWithReads.some((r) => (r instanceof compiler.PropertyRead || r instanceof compiler.SafePropertyRead) && r.name === read.name);
}
}
/**
* Emulates an access to a given field using the TypeScript `ts.Type`
* of the given class. The resolved symbol of the access is returned.
*/
function traverseReceiverAndLookupSymbol(readOrWrite, componentClass, checker) {
const path = [readOrWrite.name];
let node = readOrWrite;
while (node.receiver instanceof compiler.PropertyRead) {
node = node.receiver;
path.unshift(node.name);
}
if (!(node.receiver instanceof compiler.ImplicitReceiver)) {
return null;
}
const classType = checker.getTypeAtLocation(componentClass.name);
return (lookupPropertyAccess(checker, classType, path, {
// Necessary to avoid breaking the resolution if there is
// some narrowing involved. E.g. `myClass ? myClass.input`.
ignoreNullability: true,
})?.symbol ?? null);
}
/** Whether the given node refers to a two-way binding AST node. */
function isTwoWayBindingNode(node) {
return ((node instanceof compiler.TmplAstBoundAttribute && node.type === compiler.BindingType.TwoWay) ||
(node instanceof compiler.TmplAstBoundEvent && node.type === compiler.ParsedEventType.TwoWay));
}
/** Possible types of references to known fields detected. */
exports.ReferenceKind = void 0;
(function (ReferenceKind) {
ReferenceKind[ReferenceKind["InTemplate"] = 0] = "InTemplate";
ReferenceKind[ReferenceKind["InHostBinding"] = 1] = "InHostBinding";
ReferenceKind[ReferenceKind["TsReference"] = 2] = "TsReference";
ReferenceKind[ReferenceKind["TsClassTypeReference"] = 3] = "TsClassTypeReference";
})(exports.ReferenceKind || (exports.ReferenceKind = {}));
/** Whether the given reference is a TypeScript reference. */
function isTsReference(ref) {
return ref.kind === exports.ReferenceKind.TsReference;
}
/** Whether the given reference is a template reference. */
function isTemplateReference(ref) {
return ref.kind === exports.ReferenceKind.InTemplate;
}
/** Whether the given reference is a host binding reference. */
function isHostBindingReference(ref) {
return ref.kind === exports.ReferenceKind.InHostBinding;
}
/**
* Whether the given reference is a TypeScript `ts.Type` reference
* to a class containing known fields.
*/
function isTsClassTypeReference(ref) {
return ref.kind === exports.ReferenceKind.TsClassTypeReference;
}
/**
* Checks host bindings of the given class and tracks all
* references to inputs within bindings.
*/
function identifyHostBindingReferences(node, programInfo, checker, reflector, result, knownFields, fieldNamesToConsiderForReferenceLookup) {
if (node.name === undefined) {
return;
}
const decorators = reflector.getDecoratorsOfDeclaration(node);
if (decorators === null) {
return;
}
const angularDecorators = migrations.getAngularDecorators(decorators, ['Directive', 'Component'],
/* isAngularCore */ false);
if (angularDecorators.length === 0) {
return;
}
// Assume only one Angular decorator per class.
const ngDecorator = angularDecorators[0];
if (ngDecorator.args?.length !== 1) {
return;
}
const metadataNode = migrations.unwrapExpression(ngDecorator.args[0]);
if (!ts.isObjectLiteralExpression(metadataNode)) {
return;
}
const metadata = migrations.reflectObjectLiteral(metadataNode);
if (!metadata.has('host')) {
return;
}
let hostField = migrations.unwrapExpression(metadata.get('host'));
// Special-case in case host bindings are shared via a variable.
// e.g. Material button shares host bindings as a constant in the same target.
if (ts.isIdentifier(hostField)) {
let symbol = checker.getSymbolAtLocation(hostField);
// Plain identifier references can point to alias symbols (e.g. imports).
if (symbol !== undefined && symbol.flags & ts.SymbolFlags.Alias) {
symbol = checker.getAliasedSymbol(symbol);
}
if (symbol !== undefined &&
symbol.valueDeclaration !== undefined &&
ts.isVariableDeclaration(symbol.valueDeclaration)) {
hostField = symbol?.valueDeclaration.initializer;
}
}
if (hostField === undefined || !ts.isObjectLiteralExpression(hostField)) {
return;
}
const hostMap = migrations.reflectObjectLiteral(hostField);
const expressionResult = [];
const expressionVisitor = new TemplateExpressionReferenceVisitor(checker, null, node, knownFields, fieldNamesToConsiderForReferenceLookup);
for (const [rawName, expression] of hostMap.entries()) {
if (!ts.isStringLiteralLike(expression)) {
continue;
}
const isEventBinding = rawName.startsWith('(');
const isPropertyBinding = rawName.startsWith('[');
// Only migrate property or event bindings.
if (!isPropertyBinding && !isEventBinding) {
continue;
}
const parser = compiler.makeBindingParser();
const sourceSpan = new compiler.ParseSourceSpan(
// Fake source span to keep parsing offsets zero-based.
// We then later combine these with the expression TS node offsets.
new compiler.ParseLocation({ content: '', url: '' }, 0, 0, 0), new compiler.ParseLocation({ content: '', url: '' }, 0, 0, 0));
const name = rawName.substring(1, rawName.length - 1);
let parsed = undefined;
if (isEventBinding) {
const result = [];
parser.parseEvent(name.substring(1, name.length - 1), expression.text, false, sourceSpan, sourceSpan, [], result, sourceSpan);
parsed = result[0].handler;
}
else {
const result = [];
parser.parsePropertyBinding(name, expression.text, true,
/* isTwoWayBinding */ false, sourceSpan, 0, sourceSpan, [], result, sourceSpan);
parsed = result[0].expression;
}
if (parsed != null) {
expressionResult.push(...expressionVisitor.checkTemplateExpression(expression, parsed));
}
}
for (const ref of expressionResult) {
result.references.push({
kind: exports.ReferenceKind.InHostBinding,
from: {
read: ref.read,
readAstPath: ref.readAstPath,
isObjectShorthandExpression: ref.isObjectShorthandExpression,
isWrite: ref.isWrite,
file: project_paths.projectFile(ref.context.getSourceFile(), programInfo),
hostPropertyNode: ref.context,
},
target: ref.targetField,
});
}
}
/**
* Attempts to extract the `TemplateDefinition` for the given
* class, if possible.
*
* The definition can then be used with the Angular compiler to
* load/parse the given template.
*/
function attemptExtractTemplateDefinition(node, checker, reflector, resourceLoader) {
const classDecorators = reflector.getDecoratorsOfDeclaration(node);
const evaluator = new migrations.PartialEvaluator(reflector, checker, null);
const ngDecorators = classDecorators !== null
? migrations.getAngularDecorators(classDecorators, ['Component'], /* isAngularCore */ false)
: [];
if (ngDecorators.length === 0 ||
ngDecorators[0].args === null ||
ngDecorators[0].args.length === 0 ||
!ts.isObjectLiteralExpression(ngDecorators[0].args[0])) {
return null;
}
const properties = migrations.reflectObjectLiteral(ngDecorators[0].args[0]);
const templateProp = properties.get('template');
const templateUrlProp = properties.get('templateUrl');
const containingFile = node.getSourceFile().fileName;
// inline template.
if (templateProp !== undefined) {
const templateStr = evaluator.evaluate(templateProp);
if (typeof templateStr === 'string') {
return {
isInline: true,
expression: templateProp,
preserveWhitespaces: false,
resolvedTemplateUrl: containingFile,
templateUrl: containingFile,
};
}
}
try {
// external template.
if (templateUrlProp !== undefined) {
const templateUrl = evaluator.evaluate(templateUrlProp);
if (typeof templateUrl === 'string') {
return {
isInline: false,
preserveWhitespaces: false,
templateUrlExpression: templateUrlProp,
templateUrl,
resolvedTemplateUrl: resourceLoader.resolve(templateUrl, containingFile),
};
}
}
}
catch (e) {
console.error(`Could not parse external template: ${e}`);
}
return null;
}
/**
* Checks whether the given class has an Angular template, and resolves
* all of the references to inputs.
*/
function identifyTemplateReferences(programInfo, node, reflector, checker, evaluator, templateTypeChecker, resourceLoader, options, result, knownFields, fieldNamesToConsiderForReferenceLookup) {
const template = templateTypeChecker.getTemplate(node, compilerCli.OptimizeFor.WholeProgram) ??
// If there is no template registered in the TCB or compiler, the template may
// be skipped due to an explicit `jit: true` setting. We try to detect this case
// and parse the template manually.
extractTemplateWithoutCompilerAnalysis(node, checker, reflector, resourceLoader, evaluator, options);
if (template !== null) {
const visitor = new TemplateReferenceVisitor(checker, templateTypeChecker, node, knownFields, fieldNamesToConsiderForReferenceLookup);
template.forEach((node) => node.visit(visitor));
for (const res of visitor.result) {
const templateFilePath = res.context.sourceSpan.start.file.url;
// Templates without an URL are non-mappable artifacts of e.g.
// string concatenated templates. See the `indirect` template
// source mapping concept in the compiler. We skip such references
// as those cannot be migrated, but print an error for now.
if (templateFilePath === '') {
// TODO: Incorporate a TODO potentially.
console.error(`Found reference to field ${res.targetField.key} that cannot be ` +
`migrated because the template cannot be parsed with source map information ` +
`(in file: ${node.getSourceFile().fileName}).`);
continue;
}
result.references.push({
kind: exports.ReferenceKind.InTemplate,
from: {
read: res.read,
readAstPath: res.readAstPath,
node: res.context,
isObjectShorthandExpression: res.isObjectShorthandExpression,
originatingTsFile: project_paths.projectFile(node.getSourceFile(), programInfo),
templateFile: project_paths.projectFile(compilerCli.absoluteFrom(templateFilePath), programInfo),
isLikelyPartOfNarrowing: res.isLikelyNarrowed,
isWrite: res.isWrite,
},
target: res.targetField,
});
}
}
}
/**
* Attempts to extract a `@Component` template from the given class,
* without relying on the `NgCompiler` program analysis.
*
* This is useful for JIT components using `jit: true` which were not
* processed by the Angular compiler, but may still have templates that
* contain references to inputs that we can resolve via the fallback
* reference resolutions (that does not use the type check block).
*/
function extractTemplateWithoutCompilerAnalysis(node, checker, reflector, resourceLoader, evaluator, options) {
if (node.name === undefined) {
return null;
}
const tmplDef = attemptExtractTemplateDefinition(node, checker, reflector, resourceLoader);
if (tmplDef === null) {
return null;
}
return migrations.extractTemplate(node, tmplDef, evaluator, null, resourceLoader, {
enableBlockSyntax: true,
enableLetSyntax: true,
usePoisonedData: true,
enableI18nLegacyMessageIdFormat: options.enableI18nLegacyMessageIdFormat !== false,
i18nNormalizeLineEndingsInICUs: options.i18nNormalizeLineEndingsInICUs === true,
enableSelectorless: false,
}, migrations.CompilationMode.FULL).nodes;
}
/** Gets the pattern and property name for a given binding element. */
function resolveBindingElement(node) {
const name = node.propertyName ?? node.name;
// If we are discovering a non-analyzable element in the path, abort.
if (!ts.isStringLiteralLike(name) && !ts.isIdentifier(name)) {
return null;
}
return {
pattern: node.parent,
propertyName: name.text,
};
}
/** Gets the declaration node of the given binding element. */
function getBindingElementDeclaration(node) {
while (true) {
if (ts.isBindingElement(node.parent.parent)) {
node = node.parent.parent;
}
else {
return node.parent.parent;
}
}
}
/**
* Expands the given reference to its containing expression, capturing
* the full context.
*
* E.g. `traverseAccess(ref<`bla`>)` may return `this.bla`
* or `traverseAccess(ref<`bla`>)` may return `this.someObj.a.b.c.bla`.
*
* This helper is useful as we will replace the full access with a temporary
* variable for narrowing. Replacing just the identifier is wrong.
*/
function traverseAccess(access) {
if (ts.isPropertyAccessExpression(access.parent) && access.parent.name === access) {
return access.parent;
}
else if (ts.isElementAccessExpression(access.parent) &&
access.parent.argumentExpression === access) {
return access.parent;
}
return access;
}
/**
* Unwraps the parent of the given node, if it's a
* parenthesized expression or `as` expression.
*/
function unwrapParent(node) {
if (ts.isParenthesizedExpression(node.parent)) {
return unwrapParent(node.parent);
}
else if (ts.isAsExpression(node.parent)) {
return unwrapParent(node.parent);
}
return node;
}
/**
* List of binary operators that indicate a write operation.
*
* Useful for figuring out whether an expression assigns to
* something or not.
*/
const writeBinaryOperators = [
ts.SyntaxKind.EqualsToken,
ts.SyntaxKind.BarBarEqualsToken,
ts.SyntaxKind.BarEqualsToken,
ts.SyntaxKind.AmpersandEqualsToken,
ts.SyntaxKind.AmpersandAmpersandEqualsToken,
ts.SyntaxKind.SlashEqualsToken,
ts.SyntaxKind.MinusEqualsToken,
ts.SyntaxKind.PlusEqualsToken,
ts.SyntaxKind.CaretEqualsToken,
ts.SyntaxKind.PercentEqualsToken,
ts.SyntaxKind.AsteriskEqualsToken,
ts.SyntaxKind.ExclamationEqualsToken,
];
/**
* Checks whether given TypeScript reference refers to an Angular input, and captures
* the reference if possible.
*
* @param fieldNamesToConsiderForReferenceLookup List of field names that should be
* respected when expensively looking up references to known fields.
* May be null if all identifiers should be inspected.
*/
function identifyPotentialTypeScriptReference(node, programInfo, checker, knownFields, result, fieldNamesToConsiderForReferenceLookup, advisors) {
// Skip all identifiers that never can point to a migrated field.
// TODO: Capture these assumptions and performance optimizations in the design doc.
if (fieldNamesToConsiderForReferenceLookup !== null &&
!fieldNamesToConsiderForReferenceLookup.has(node.text)) {
return;
}
let target = undefined;
try {
// Resolve binding elements to their declaration symbol.
// Commonly inputs are accessed via object expansion. e.g. `const {input} = this;`.
if (ts.isBindingElement(node.parent)) {
// Skip binding elements that are using spread.
if (node.parent.dotDotDotToken !== undefined) {
return;
}
const bindingInfo = resolveBindingElement(node.parent);
if (bindingInfo === null) {
// The declaration could not be resolved. Skip analyzing this.
return;
}
const bindingType = checker.getTypeAtLocation(bindingInfo.pattern);
const resolved = lookupPropertyAccess(checker, bindingType, [bindingInfo.propertyName]);
target = resolved?.symbol;
}
else {
target = checker.getSymbolAtLocation(node);
}
}
catch (e) {
console.error('Unexpected error while trying to resolve identifier reference:');
console.error(e);
// Gracefully skip analyzing. This can happen when e.g. a reference is named similar
// to an input, but is dependant on `.d.ts` that is not necessarily available (clutz dts).
return;
}
noTargetSymbolCheck: if (target === undefined) {
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
const propAccessSymbol = checker.getSymbolAtLocation(node.parent.expression);
if (propAccessSymbol !== undefined &&
propAccessSymbol.valueDeclaration !== undefined &&
ts.isVariableDeclaration(propAccessSymbol.valueDeclaration) &&
propAccessSymbol.valueDeclaration.initializer !== undefined) {
target = advisors.debugElComponentInstanceTracker
.detect(propAccessSymbol.valueDeclaration.initializer)
?.getProperty(node.text);
// We found a target in the fallback path. Break out.
if (target !== undefined) {
break noTargetSymbolCheck;
}
}
}
return;
}
let targetInput = knownFields.attemptRetrieveDescriptorFromSymbol(target);
if (targetInput === null) {
return;
}
const access = unwrapParent(traverseAccess(node));
const accessParent = access.parent;
const isWriteReference = ts.isBinaryExpression(accessParent) &&
accessParent.left === access &&
writeBinaryOperators.includes(accessParent.operatorToken.kind);
// track accesses from source files to known fields.
result.references.push({
kind: exports.ReferenceKind.TsReference,
from: {
node,
file: project_paths.projectFile(node.getSourceFile(), programInfo),
isWrite: isWriteReference,
isPartOfElementBinding: ts.isBindingElement(node.parent),
},
target: targetInput,
});
}
/**
* Phase where we iterate through all source file references and
* detect references to known fields (e.g. commonly inputs).
*
* This is useful, for example in the signal input migration whe
* references need to be migrated to unwrap signals, given that
* their target properties is no longer holding a raw value, but
* instead an `InputSignal`.
*
* This phase detects references in all types of locations:
* - TS source files
* - Angular templates (inline or external)
* - Host binding expressions.
*/
function createFindAllSourceFileReferencesVisitor(programInfo, checker, reflector, resourceLoader, evaluator, templateTypeChecker, knownFields, fieldNamesToConsiderForReferenceLookup, result) {
const debugElComponentInstanceTracker = new DebugElementComponentInstance(checker);
const partialDirectiveCatalystTracker = new PartialDirectiveTypeInCatalystTests(checker, knownFields);
const perfCounters = {
template: 0,
hostBindings: 0,
tsReferences: 0,
tsTypes: 0,
};
// Schematic NodeJS execution may not have `global.performance` defined.
const currentTimeInMs = () => typeof global.performance !== 'undefined' ? global.performance.now() : Date.now();
const visitor = (node) => {
let lastTime = currentTimeInMs();
// Note: If there is no template type checker and resource loader, we aren't processing
// an Angular program, and can skip template detection.
if (ts.isClassDeclaration(node) && templateTypeChecker !== null && resourceLoader !== null) {
identifyTemplateReferences(programInfo, node, reflector, checker, evaluator, templateTypeChecker, resourceLoader, programInfo.userOptions, result, knownFields, fieldNamesToConsiderForReferenceLookup);
perfCounters.template += (currentTimeInMs() - lastTime) / 1000;
lastTime = currentTimeInMs();
identifyHostBindingReferences(node, programInfo, checker, reflector, result, knownFields, fieldNamesToConsiderForReferenceLookup);
perfCounters.hostBindings += (currentTimeInMs() - lastTime) / 1000;
lastTime = currentTimeInMs();
}
lastTime = currentTimeInMs();
// find references, but do not capture input declarations itself.
if (ts.isIdentifier(node) &&
!(isInputContainerNode(node.parent) && node.parent.name === node)) {
identifyPotentialTypeScriptReference(node, programInfo, checker, knownFields, result, fieldNamesToConsiderForReferenceLookup, {
debugElComponentInstanceTracker,
});
}
perfCounters.tsReferences += (currentTimeInMs() - lastTime) / 1000;
lastTime = currentTimeInMs();
// Detect `Partial<T>` references.
// Those are relevant to be tracked as they may be updated in Catalyst to
// unwrap signal inputs. Commonly people use `Partial` in Catalyst to type
// some "component initial values".
const partialDirectiveInCatalyst = partialDirectiveCatalystTracker.detect(node);
if (partialDirectiveInCatalyst !== null) {
result.references.push({
kind: exports.ReferenceKind.TsClassTypeReference,
from: {
file: project_paths.projectFile(partialDirectiveInCatalyst.referenceNode.getSourceFile(), programInfo),
node: partialDirectiveInCatalyst.referenceNode,
},
isPartialReference: true,
isPartOfCatalystFile: true,
target: partialDirectiveInCatalyst.targetClass,
});
}
perfCounters.tsTypes += (currentTimeInMs() - lastTime) / 1000;
};
return {
visitor,
debugPrintMetrics: () => {
console.info('Source file analysis performance', perfCounters);
},
};
}
exports.createFindAllSourceFileReferencesVisitor = createFindAllSourceFileReferencesVisitor;
exports.getBindingElementDeclaration = getBindingElementDeclaration;
exports.getMemberName = getMemberName;
exports.isHostBindingReference = isHostBindingReference;
exports.isInputContainerNode = isInputContainerNode;
exports.isTemplateReference = isTemplateReference;
exports.isTsClassTypeReference = isTsClassTypeReference;
exports.isTsReference = isTsReference;
exports.traverseAccess = traverseAccess;
exports.unwrapParent = unwrapParent;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display