@@ -15,27 +15,31 @@ function insertDebugNameIntoCallExpression(
1515 const signalExpressionIsRequired = isRequiredSignalFunction ( callExpression . expression ) ;
1616 let configPosition = signalExpressionIsRequired ? 0 : 1 ;
1717
18+ const nodeArgs = Array . from ( callExpression . arguments ) ;
19+
1820 // 1. If the call expression has no arguments, we pretend that the config object is at position 0.
1921 // We do this so that we can insert a spread element at the start of the args list in a way where
2022 // undefined can be the first argument but still get tree-shaken out in production builds.
2123 // or
22- // 2. If the signal has an object-only definition (e.g. `linkedSignal` or `resource`), we set
23- // the argument position to 0, i.e. reusing the existing object.
24+ // 2. Since `linkedSignal` with computation uses a single object for both computation logic
25+ // and options (unlike other signal-based primitives), we set the argument position to 0, i.e.
26+ // reusing the computation logic object.
2427 const signalExpressionHasNoArguments = callExpression . arguments . length === 0 ;
25- const signalWithObjectOnlyDefinition = isSignalWithObjectOnlyDefinition ( callExpression ) ;
26- if ( signalExpressionHasNoArguments || signalWithObjectOnlyDefinition ) {
28+ const isLinkedSignal = callExpression . expression . getText ( ) === 'linkedSignal' ;
29+ const isComputationLinkedSignal =
30+ isLinkedSignal && nodeArgs [ 0 ] . kind === ts . SyntaxKind . ObjectLiteralExpression ;
31+ if ( signalExpressionHasNoArguments || isComputationLinkedSignal ) {
2732 configPosition = 0 ;
2833 }
2934
30- const nodeArgs = Array . from ( callExpression . arguments ) ;
3135 let existingArgument = nodeArgs [ configPosition ] ;
3236
3337 if ( existingArgument === undefined ) {
3438 existingArgument = ts . factory . createObjectLiteralExpression ( [ ] ) ;
3539 }
3640
3741 // Do nothing if an identifier is used as the config object
38- // Ex:
42+ // Ex -
3943 // const defaultObject = { equals: () => false };
4044 // signal(123, defaultObject)
4145 if ( ts . isIdentifier ( existingArgument ) ) {
@@ -100,18 +104,15 @@ function insertDebugNameIntoCallExpression(
100104
101105 let transformedSignalArgs : ts . NodeArray < ts . Expression > ;
102106
103- if (
104- signalExpressionIsRequired ||
105- signalExpressionHasNoArguments ||
106- signalWithObjectOnlyDefinition
107- ) {
107+ if ( signalExpressionIsRequired || signalExpressionHasNoArguments || isComputationLinkedSignal ) {
108108 // 1. If the call expression is a required signal function, there is no args other than the config object.
109109 // So we just use the spread element as the only argument.
110110 // or
111111 // 2. If the call expression has no arguments (ex. input(), model(), etc), we already added the undefined
112112 // identifier in the spread element above. So we use that spread Element as is.
113113 // or
114- // 3. We are transforming a signal with object-only definition.
114+ // 3. We are transforming a `linkedSignal` with computation (i.e. we have a single object for both
115+ // logic and options).
115116 transformedSignalArgs = ts . factory . createNodeArray ( [ spreadElementContainingUpdatedOptions ] ) ;
116117 } else {
117118 // 3. Signal expression is not required and has arguments.
@@ -233,23 +234,6 @@ function isPropertyDeclarationCase(
233234 return ts . isIdentifier ( expression ) && isSignalFunction ( expression ) ;
234235}
235236
236- type PackageName = 'core' | 'common' ;
237-
238- const signalFunctions : ReadonlyMap < string , PackageName > = new Map ( [
239- [ 'signal' , 'core' ] ,
240- [ 'computed' , 'core' ] ,
241- [ 'linkedSignal' , 'core' ] ,
242- [ 'input' , 'core' ] ,
243- [ 'model' , 'core' ] ,
244- [ 'viewChild' , 'core' ] ,
245- [ 'viewChildren' , 'core' ] ,
246- [ 'contentChild' , 'core' ] ,
247- [ 'contentChildren' , 'core' ] ,
248- [ 'effect' , 'core' ] ,
249- [ 'resource' , 'core' ] ,
250- [ 'httpResource' , 'common' ] ,
251- ] ) ;
252-
253237/**
254238 *
255239 * Determines if a node is an expression that references an @angular/core imported symbol.
@@ -259,7 +243,7 @@ const signalFunctions: ReadonlyMap<string, PackageName> = new Map([
259243 * const mySignal = signal(123); // expressionIsUsingAngularImportedSymbol === true
260244 * ```
261245 */
262- function expressionIsUsingAngularImportedSymbol (
246+ function expressionIsUsingAngularCoreImportedSymbol (
263247 program : ts . Program ,
264248 expression : ts . Expression ,
265249) : boolean {
@@ -298,14 +282,25 @@ function expressionIsUsingAngularImportedSymbol(
298282 }
299283
300284 const specifier = importDeclaration . moduleSpecifier . text ;
301- const packageName = signalFunctions . get ( expression . getText ( ) ) ;
302285 return (
303286 specifier !== undefined &&
304- packageName !== undefined &&
305- ( specifier === `@angular/${ packageName } ` || specifier . startsWith ( `@angular/${ packageName } /` ) )
287+ ( specifier === '@angular/core' || specifier . startsWith ( '@angular/core/' ) )
306288 ) ;
307289}
308290
291+ const signalFunctions : ReadonlySet < string > = new Set ( [
292+ 'signal' ,
293+ 'computed' ,
294+ 'linkedSignal' ,
295+ 'input' ,
296+ 'model' ,
297+ 'viewChild' ,
298+ 'viewChildren' ,
299+ 'contentChild' ,
300+ 'contentChildren' ,
301+ 'effect' ,
302+ ] ) ;
303+
309304function isSignalFunction ( expression : ts . Identifier ) : boolean {
310305 const text = expression . text ;
311306
@@ -336,10 +331,10 @@ function transformVariableDeclaration(
336331
337332 const expression = node . initializer . expression ;
338333 if ( ts . isPropertyAccessExpression ( expression ) ) {
339- if ( ! expressionIsUsingAngularImportedSymbol ( program , expression . expression ) ) {
334+ if ( ! expressionIsUsingAngularCoreImportedSymbol ( program , expression . expression ) ) {
340335 return node ;
341336 }
342- } else if ( ! expressionIsUsingAngularImportedSymbol ( program , expression ) ) {
337+ } else if ( ! expressionIsUsingAngularCoreImportedSymbol ( program , expression ) ) {
343338 return node ;
344339 }
345340
@@ -367,10 +362,10 @@ function transformPropertyAssignment(
367362) : ts . ExpressionStatement {
368363 const expression = node . expression . right . expression ;
369364 if ( ts . isPropertyAccessExpression ( expression ) ) {
370- if ( ! expressionIsUsingAngularImportedSymbol ( program , expression . expression ) ) {
365+ if ( ! expressionIsUsingAngularCoreImportedSymbol ( program , expression . expression ) ) {
371366 return node ;
372367 }
373- } else if ( ! expressionIsUsingAngularImportedSymbol ( program , expression ) ) {
368+ } else if ( ! expressionIsUsingAngularCoreImportedSymbol ( program , expression ) ) {
374369 return node ;
375370 }
376371
@@ -392,10 +387,10 @@ function transformPropertyDeclaration(
392387
393388 const expression = node . initializer . expression ;
394389 if ( ts . isPropertyAccessExpression ( expression ) ) {
395- if ( ! expressionIsUsingAngularImportedSymbol ( program , expression . expression ) ) {
390+ if ( ! expressionIsUsingAngularCoreImportedSymbol ( program , expression . expression ) ) {
396391 return node ;
397392 }
398- } else if ( ! expressionIsUsingAngularImportedSymbol ( program , expression ) ) {
393+ } else if ( ! expressionIsUsingAngularCoreImportedSymbol ( program , expression ) ) {
399394 return node ;
400395 }
401396
@@ -415,24 +410,6 @@ function transformPropertyDeclaration(
415410 }
416411}
417412
418- /**
419- * The function determines whether the target signal has an object-only definition, that includes
420- * both the computation logic and the options (unlike other signal-based primitives), or not.
421- * Ex: `linkedSignal` with computation, `resource`
422- */
423- function isSignalWithObjectOnlyDefinition ( callExpression : ts . CallExpression ) : boolean {
424- const callExpressionText = callExpression . expression . getText ( ) ;
425- const nodeArgs = Array . from ( callExpression . arguments ) ;
426-
427- const isLinkedSignal = callExpressionText === 'linkedSignal' ;
428- const isComputationLinkedSignal =
429- isLinkedSignal && nodeArgs [ 0 ] . kind === ts . SyntaxKind . ObjectLiteralExpression ;
430-
431- const isResource = callExpressionText === 'resource' ;
432-
433- return isComputationLinkedSignal || isResource ;
434- }
435-
436413/**
437414 *
438415 * This transformer adds a debugName property to the config object of signal functions like
0 commit comments