@@ -21,6 +21,14 @@ import { parseStringLiteral } from './string-literal';
21
21
import { parseStaticStyles } from './styles' ;
22
22
import { parseStaticWatchers } from './watchers' ;
23
23
24
+ const BLACKLISTED_COMPONENT_METHODS = [
25
+ /**
26
+ * If someone would define a getter called "shadowRoot" on a component
27
+ * this would cause issues when Stencil tries to hydrate the component.
28
+ */
29
+ 'shadowRoot' ,
30
+ ] ;
31
+
24
32
/**
25
33
* Given a {@see ts.ClassDeclaration} which represents a Stencil component
26
34
* class declaration, parse and format various pieces of data about static class
@@ -148,6 +156,8 @@ export const parseStaticComponentMeta = (
148
156
} ;
149
157
150
158
const visitComponentChildNode = ( node : ts . Node ) => {
159
+ validateComponentMembers ( node ) ;
160
+
151
161
if ( ts . isCallExpression ( node ) ) {
152
162
parseCallExpression ( cmp , node ) ;
153
163
} else if ( ts . isStringLiteral ( node ) ) {
@@ -176,6 +186,44 @@ export const parseStaticComponentMeta = (
176
186
return cmpNode ;
177
187
} ;
178
188
189
+ const validateComponentMembers = ( node : ts . Node ) => {
190
+ /**
191
+ * validate if:
192
+ */
193
+ if (
194
+ /**
195
+ * the component has a getter called "shadowRoot"
196
+ */
197
+ ts . isGetAccessorDeclaration ( node ) &&
198
+ ts . isIdentifier ( node . name ) &&
199
+ typeof node . name . escapedText === 'string' &&
200
+ BLACKLISTED_COMPONENT_METHODS . includes ( node . name . escapedText ) &&
201
+ /**
202
+ * the parent node is a class declaration
203
+ */
204
+ ts . isClassDeclaration ( node . parent )
205
+ ) {
206
+ const propName = node . name . escapedText ;
207
+ const decorator = ts . getDecorators ( node . parent ) [ 0 ] ;
208
+ /**
209
+ * the class is actually a Stencil component, has a decorator with a property named "tag"
210
+ */
211
+ if (
212
+ ts . isCallExpression ( decorator . expression ) &&
213
+ decorator . expression . arguments . length === 1 &&
214
+ ts . isObjectLiteralExpression ( decorator . expression . arguments [ 0 ] ) &&
215
+ decorator . expression . arguments [ 0 ] . properties . some (
216
+ ( prop ) => ts . isPropertyAssignment ( prop ) && prop . name . getText ( ) === 'tag' ,
217
+ )
218
+ ) {
219
+ const componentName = node . parent . name . getText ( ) ;
220
+ throw new Error (
221
+ `The component "${ componentName } " has a getter called "${ propName } ". This getter is reserved for use by Stencil components and should not be defined by the user.` ,
222
+ ) ;
223
+ }
224
+ }
225
+ } ;
226
+
179
227
const parseVirtualProps = ( docs : d . CompilerJsDoc ) => {
180
228
return docs . tags
181
229
. filter ( ( { name } ) => name === 'virtualProp' )
0 commit comments