@@ -859,6 +859,28 @@ fn parse_query_config<'a>(
859859 source_text : Option < & ' a str > ,
860860 consts : Option < & super :: StringConsts < ' a > > ,
861861) -> QueryConfig < ' a > {
862+ // With the file, read like ngtsc does (see [`member_query`]). A query it
863+ // rejects isn't compiled; [`member_query_error`] reports it.
864+ if let Some ( consts) = consts {
865+ return match member_query (
866+ allocator,
867+ decorator,
868+ decorator_name,
869+ Span :: default ( ) ,
870+ source_text,
871+ consts,
872+ ) {
873+ Ok ( query) => QueryConfig {
874+ predicate : Some ( query. predicate ) ,
875+ is_static : query. is_static ,
876+ read : query. read ,
877+ descendants : query. descendants ,
878+ emit_distinct_changes_only : query. emit_distinct_changes_only ,
879+ } ,
880+ Err ( _) => QueryConfig :: default_for ( decorator_name) ,
881+ } ;
882+ }
883+
862884 let Expression :: CallExpression ( call) = & decorator. expression else {
863885 return QueryConfig :: default_for ( decorator_name) ;
864886 } ;
@@ -869,27 +891,16 @@ fn parse_query_config<'a>(
869891
870892 let mut config = QueryConfig :: default_for ( decorator_name) ;
871893
872- // The predicate: a string selector, a string array, or a type/token.
894+ // The predicate: a string selector or a type/token.
873895 // forwardRef isn't included in compiled output.
874- let node = try_unwrap_forward_ref ( first_arg, consts) . unwrap_or ( first_arg) ;
875- let selectors = match ( consts, node) {
876- ( Some ( consts) , _) => match super :: evaluator:: Evaluator :: new ( consts) . evaluate ( node) {
877- super :: evaluator:: Value :: String ( s) => Some ( std:: vec![ s] ) ,
878- super :: evaluator:: Value :: Array ( items) => {
879- items. iter ( ) . map ( |i| i. as_str ( ) . map ( str:: to_string) ) . collect ( )
880- }
881- _ => None ,
882- } ,
883- ( None , Expression :: StringLiteral ( lit) ) => Some ( std:: vec![ lit. value. to_string( ) ] ) ,
884- _ => None ,
885- } ;
886- config. predicate = match selectors {
887- Some ( selectors) => {
896+ let node = try_unwrap_forward_ref ( first_arg, None ) . unwrap_or ( first_arg) ;
897+ config. predicate = match node {
898+ Expression :: StringLiteral ( lit) => {
888899 let mut list = Vec :: new_in ( & allocator) ;
889- list. extend ( selectors . iter ( ) . map ( |s| Ident :: from ( allocator . alloc_str ( s ) ) ) ) ;
900+ list. push ( lit . value . clone ( ) . into ( ) ) ;
890901 Some ( QueryPredicate :: Selectors ( list) )
891902 }
892- None => convert_oxc_expression ( allocator, node, source_text) . map ( QueryPredicate :: Type ) ,
903+ _ => convert_oxc_expression ( allocator, node, source_text) . map ( QueryPredicate :: Type ) ,
893904 } ;
894905
895906 // Parse options from second argument if present
@@ -1798,8 +1809,9 @@ pub(crate) fn parse_decorator_queries<'a>(
17981809 consts,
17991810 & evaluator,
18001811 type_name,
1801- new_expr,
1802- property_name,
1812+ & new_expr. arguments ,
1813+ new_expr. span ,
1814+ & property_name,
18031815 source_text,
18041816 ) {
18051817 Ok ( query) if type_name. starts_with ( "Content" ) => {
@@ -1849,21 +1861,71 @@ pub(crate) fn parse_decorator_queries<'a>(
18491861 queries
18501862}
18511863
1852- /// One `new ViewChild(predicate, options?)` and friends. An error comes with
1853- /// the node ngtsc reports it on.
1864+ /// A query member decorator (`@ViewChild('el', {static: true})` on the
1865+ /// member at `span`), read like ngtsc's `extractDecoratorQueryMetadata` (see
1866+ /// [`decorator_query`]): the options are evaluated, so a same-file `const`
1867+ /// counts and a value of the wrong type is an error.
1868+ fn member_query < ' a > (
1869+ allocator : & ' a Allocator ,
1870+ decorator : & ' a Decorator < ' a > ,
1871+ name : & str ,
1872+ span : Span ,
1873+ source_text : Option < & ' a str > ,
1874+ consts : & super :: StringConsts < ' a > ,
1875+ ) -> Result < R3QueryMetadata < ' a > , ( String , Span ) > {
1876+ // `@ViewChild` without a call has no arguments.
1877+ let args: & ' a [ Argument < ' a > ] = match & decorator. expression {
1878+ Expression :: CallExpression ( call) => & call. arguments ,
1879+ _ => & [ ] ,
1880+ } ;
1881+ let evaluator = super :: evaluator:: Evaluator :: new ( consts) ;
1882+ decorator_query ( allocator, consts, & evaluator, name, args, span, "" , source_text)
1883+ }
1884+
1885+ /// The first error ngtsc raises for a class's query member decorators
1886+ /// (`parseQueriesOfClassFields`), in member order: the one
1887+ /// [`member_query`] reports, on the node ngtsc points at.
1888+ pub ( crate ) fn member_query_error < ' a > (
1889+ allocator : & ' a Allocator ,
1890+ class : & ' a Class < ' a > ,
1891+ source_text : Option < & ' a str > ,
1892+ consts : & super :: StringConsts < ' a > ,
1893+ ) -> Option < ( String , Span ) > {
1894+ class. body . body . iter ( ) . find_map ( |element| {
1895+ let ( decorators, span) = match element {
1896+ ClassElement :: PropertyDefinition ( prop) => ( & prop. decorators , prop. span ) ,
1897+ ClassElement :: MethodDefinition ( method)
1898+ if matches ! ( method. kind, MethodDefinitionKind :: Set | MethodDefinitionKind :: Get ) =>
1899+ {
1900+ ( & method. decorators , method. span )
1901+ }
1902+ _ => return None ,
1903+ } ;
1904+ let ( decorator, name) = QUERY_TYPES . iter ( ) . find_map ( |name| {
1905+ Some ( ( find_decorator_by_name ( decorators, name, Some ( consts) ) ?, * name) )
1906+ } ) ?;
1907+ member_query ( allocator, decorator, name, span, source_text, consts) . err ( )
1908+ } )
1909+ }
1910+
1911+ /// ngtsc's `extractDecoratorQueryMetadata`: one `@ViewChild(predicate,
1912+ /// options?)` member decorator, or `new ViewChild(...)` in `queries:`, and
1913+ /// friends. `args` are its arguments and `span` the member or the `new`
1914+ /// expression. An error comes with the node ngtsc reports it on.
1915+ #[ expect( clippy:: too_many_arguments) ]
18541916fn decorator_query < ' a > (
18551917 allocator : & ' a Allocator ,
18561918 consts : & super :: StringConsts < ' a > ,
18571919 evaluator : & super :: evaluator:: Evaluator < ' _ , ' a > ,
18581920 name : & str ,
1859- new_expr : & ' a oxc_ast:: ast:: NewExpression < ' a > ,
1860- property_name : String ,
1921+ args : & ' a [ Argument < ' a > ] ,
1922+ span : Span ,
1923+ property_name : & str ,
18611924 source_text : Option < & ' a str > ,
18621925) -> Result < R3QueryMetadata < ' a > , ( String , Span ) > {
18631926 use super :: evaluator:: Value ;
1864- let args = & new_expr. arguments ;
18651927 let Some ( first) = args. first ( ) . and_then ( Argument :: as_expression) else {
1866- return Err ( ( format ! ( "@{name} must have arguments" ) , new_expr . span ) ) ;
1928+ return Err ( ( format ! ( "@{name} must have arguments" ) , span) ) ;
18671929 } ;
18681930 let node = try_unwrap_forward_ref ( first, Some ( consts) ) . unwrap_or ( first) ;
18691931 let at_node = |message : String | ( message, node. span ( ) ) ;
@@ -1940,7 +2002,7 @@ fn decorator_query<'a>(
19402002 }
19412003
19422004 Ok ( R3QueryMetadata {
1943- property_name : Ident :: from ( allocator. alloc_str ( & property_name) ) ,
2005+ property_name : Ident :: from ( allocator. alloc_str ( property_name) ) ,
19442006 first : name == "ViewChild" || name == "ContentChild" ,
19452007 predicate,
19462008 descendants : config. descendants ,
0 commit comments