File tree Expand file tree Collapse file tree 7 files changed +44
-23
lines changed
tests/compiler-errors/samples/render-tag-invalid-call Expand file tree Collapse file tree 7 files changed +44
-23
lines changed Original file line number Diff line number Diff line change @@ -91,6 +91,8 @@ const parse = {
91
91
`A component can have a single top-level <script> element and/or a single top-level <script context="module"> element` ,
92
92
'invalid-render-expression' : ( ) => '{@render ...} tags can only contain call expressions' ,
93
93
'invalid-render-arguments' : ( ) => 'expected at most one argument' ,
94
+ 'invalid-render-call' : ( ) =>
95
+ 'Calling a snippet function using apply, bind or call is not allowed' ,
94
96
'invalid-render-spread-argument' : ( ) => 'cannot use spread arguments in {@render ...} tags' ,
95
97
'invalid-snippet-rest-parameter' : ( ) =>
96
98
'snippets do not support rest parameters; use an array instead'
Original file line number Diff line number Diff line change 4
4
get_parent ,
5
5
is_expression_attribute ,
6
6
is_text_attribute ,
7
- object
7
+ object ,
8
+ unwrap_optional
8
9
} from '../../utils/ast.js' ;
9
10
import { warn } from '../../warnings.js' ;
10
11
import fuzzymatch from '../1-parse/utils/fuzzymatch.js' ;
@@ -604,16 +605,22 @@ const validation = {
604
605
} ) ;
605
606
} ,
606
607
RenderTag ( node , context ) {
607
- const raw_args =
608
- node . expression . type === 'CallExpression'
609
- ? node . expression . arguments
610
- : node . expression . expression . arguments ;
608
+ const raw_args = unwrap_optional ( node . expression ) . arguments ;
611
609
for ( const arg of raw_args ) {
612
610
if ( arg . type === 'SpreadElement' ) {
613
611
error ( arg , 'invalid-render-spread-argument' ) ;
614
612
}
615
613
}
616
614
615
+ const callee = unwrap_optional ( node . expression ) . callee ;
616
+ if (
617
+ callee . type === 'MemberExpression' &&
618
+ callee . property . type === 'Identifier' &&
619
+ [ 'bind' , 'apply' , 'call' ] . includes ( callee . property . name )
620
+ ) {
621
+ error ( node , 'invalid-render-call' ) ;
622
+ }
623
+
617
624
const is_inside_textarea = context . path . find ( ( n ) => {
618
625
return (
619
626
n . type === 'SvelteElement' &&
Original file line number Diff line number Diff line change 3
3
extract_paths ,
4
4
is_event_attribute ,
5
5
is_text_attribute ,
6
- object
6
+ object ,
7
+ unwrap_optional
7
8
} from '../../../../utils/ast.js' ;
8
9
import { binding_properties } from '../../../bindings.js' ;
9
10
import {
@@ -1864,14 +1865,8 @@ export const template_visitors = {
1864
1865
} ,
1865
1866
RenderTag ( node , context ) {
1866
1867
context . state . template . push ( '<!>' ) ;
1867
- const callee =
1868
- node . expression . type === 'CallExpression'
1869
- ? node . expression . callee
1870
- : node . expression . expression . callee ;
1871
- const raw_args =
1872
- node . expression . type === 'CallExpression'
1873
- ? node . expression . arguments
1874
- : node . expression . expression . arguments ;
1868
+ const callee = unwrap_optional ( node . expression ) . callee ;
1869
+ const raw_args = unwrap_optional ( node . expression ) . arguments ;
1875
1870
const is_reactive =
1876
1871
callee . type !== 'Identifier' || context . state . scope . get ( callee . name ) ?. kind !== 'normal' ;
1877
1872
Original file line number Diff line number Diff line change 1
1
import { walk } from 'zimmerframe' ;
2
2
import { set_scope , get_rune } from '../../scope.js' ;
3
- import { extract_identifiers , extract_paths , is_event_attribute } from '../../../utils/ast.js' ;
3
+ import {
4
+ extract_identifiers ,
5
+ extract_paths ,
6
+ is_event_attribute ,
7
+ unwrap_optional
8
+ } from '../../../utils/ast.js' ;
4
9
import * as b from '../../../utils/builders.js' ;
5
10
import is_reference from 'is-reference' ;
6
11
import {
@@ -1141,14 +1146,8 @@ const template_visitors = {
1141
1146
state . init . push ( anchor ) ;
1142
1147
state . template . push ( t_expression ( anchor_id ) ) ;
1143
1148
1144
- const callee =
1145
- node . expression . type === 'CallExpression'
1146
- ? node . expression . callee
1147
- : node . expression . expression . callee ;
1148
- const raw_args =
1149
- node . expression . type === 'CallExpression'
1150
- ? node . expression . arguments
1151
- : node . expression . expression . arguments ;
1149
+ const callee = unwrap_optional ( node . expression ) . callee ;
1150
+ const raw_args = unwrap_optional ( node . expression ) . arguments ;
1152
1151
1153
1152
const expression = /** @type {import('estree').Expression } */ ( context . visit ( callee ) ) ;
1154
1153
const snippet_function = state . options . dev
Original file line number Diff line number Diff line change @@ -361,3 +361,12 @@ export function is_simple_expression(node) {
361
361
362
362
return false ;
363
363
}
364
+
365
+ /**
366
+ * @template {import('estree').SimpleCallExpression | import('estree').MemberExpression} T
367
+ * @param {import('estree').ChainExpression & { expression : T } | T } node
368
+ * @returns {T }
369
+ */
370
+ export function unwrap_optional ( node ) {
371
+ return node . type === 'ChainExpression' ? node . expression : node ;
372
+ }
Original file line number Diff line number Diff line change
1
+ import { test } from '../../test' ;
2
+
3
+ export default test ( {
4
+ error : {
5
+ code : 'invalid-render-call' ,
6
+ message : 'Calling a snippet function using apply, bind or call is not allowed'
7
+ }
8
+ } ) ;
Original file line number Diff line number Diff line change
1
+ {@render snippet .apply (null , [1 , 2 , 3 ])}
You can’t perform that action at this time.
0 commit comments