@@ -32,32 +32,59 @@ class _State:
3232 block_type : str | None = None # "bundle" | "body" | "promise" | None
3333 promise_type : str | None = None # "vars" | "files" | "classes" | ... | None
3434 attribute_name : str | None = None # "if" | "string" | "slist" | ... | None
35+ namespace : str = "default" # "ns" | "default" | ... |
3536
36- def update (self , node ) -> "_State" :
37+ def update (self , node ):
3738 """Updates and returns the state that should apply to the children of `node`."""
39+ if node .type == "}" :
40+ assert node .parent
41+ assert node .parent .type in [
42+ "bundle_block_body" ,
43+ "promise_block_body" ,
44+ "body_block_body" ,
45+ "list" ,
46+ ]
47+ if node .parent .type != "list" :
48+ # We just ended a block
49+ self .block_type = None
50+ self .promise_type = None
51+ self .attribute_name = None
52+ return
53+ if node .type == ";" :
54+ self .attribute_name = None
55+ return
3856 if node .type == "bundle_block" :
39- return _State (block_type = "bundle" )
57+ self .block_type = "bundle"
58+ return
4059 if node .type == "body_block" :
41- return _State (block_type = "body" )
60+ self .block_type = "body"
61+ return
4262 if node .type == "promise_block" :
43- return _State (block_type = "promise" )
63+ self .block_type = "promise"
64+ return
4465 if node .type == "bundle_section" :
45- for child in node .children :
46- if child .type == "promise_guard" :
47- return _State (
48- block_type = self .block_type ,
49- promise_type = _text (child )[:- 1 ], # strip trailing ':'
50- )
51- return _State (block_type = self .block_type )
66+ # A bundle_section is always: promise_guard, [promises], [class_guarded_promises...]
67+ # The promise_guard is guaranteed to exist by the grammar
68+ guard = next ((c for c in node .children if c .type == "promise_guard" ), None )
69+ if guard is None : # Should never happen
70+ print ("ERROR: Bundle section without a promise guard" )
71+ return
72+
73+ self .promise_type = _text (guard )[:- 1 ] # strip trailing ':'
74+ return
5275 if node .type == "attribute" :
5376 for child in node .children :
5477 if child .type == "attribute_name" :
55- return _State (
56- block_type = self .block_type ,
57- promise_type = self .promise_type ,
58- attribute_name = _text (child ),
59- )
60- return self
78+ self .attribute_name = _text (child )
79+ if self .attribute_name == "namespace" :
80+ self .namespace = _text (child .next_named_sibling ).strip ("\" '" )
81+ return
82+ return
83+
84+ @staticmethod
85+ def qualify (name : str , namespace : str ) -> str :
86+ """If name is already qualified (contains ':'), return as-is. Otherwise prepend namespace."""
87+ return name if ":" in name else f"{ namespace } :{ name } "
6188
6289
6390def lint_cfbs_json (filename ) -> int :
@@ -184,7 +211,8 @@ def _node_checks(filename, lines, node, user_definition, strict, state: _State):
184211 if node .type == "calling_identifier" :
185212 if (
186213 strict
187- and _text (node ) in user_definition .get ("all_bundle_names" , set ())
214+ and state .qualify (_text (node ), state .namespace )
215+ in user_definition .get ("all_bundle_names" , set ())
188216 and state .promise_type in user_definition .get ("custom_promise_types" , set ())
189217 ):
190218 _highlight_range (node , lines )
@@ -193,11 +221,12 @@ def _node_checks(filename, lines, node, user_definition, strict, state: _State):
193221 )
194222 return 1
195223 if strict and (
196- _text (node )
197- not in BUILTIN_FUNCTIONS .union (
224+ state . qualify ( _text (node ), state . namespace )
225+ not in set .union (
198226 user_definition .get ("all_bundle_names" , set ()),
199227 user_definition .get ("all_body_names" , set ()),
200228 )
229+ and _text (node ) not in BUILTIN_FUNCTIONS
201230 ):
202231 _highlight_range (node , lines )
203232 print (
@@ -215,11 +244,9 @@ def _stateful_walk(
215244
216245 errors = _node_checks (filename , lines , node , user_definition , strict , state )
217246
218- child_state = state .update (node )
247+ state .update (node )
219248 for child in node .children :
220- errors += _stateful_walk (
221- filename , lines , child , user_definition , strict , child_state
222- )
249+ errors += _stateful_walk (filename , lines , child , user_definition , strict , state )
223250 return errors
224251
225252
@@ -239,18 +266,55 @@ def _walk(filename, lines, node, user_definition=None, strict=True) -> int:
239266 line = node .range .start_point [0 ] + 1
240267 column = node .range .start_point [1 ] + 1
241268
242- return _stateful_walk (filename , lines , node , user_definition , strict )
269+ state = _State ()
270+ ret = _stateful_walk (filename , lines , node , user_definition , strict , state = state )
271+ state = _State () # Clear state
272+ return ret
243273
244274
245275def _parse_user_definition (filename , lines , root_node ):
246- promise_blocks = _find_node_type (filename , lines , root_node , "promise_block_name" )
247- bundle_blocks = _find_node_type (filename , lines , root_node , "bundle_block_name" )
248- body_blocks = _find_node_type (filename , lines , root_node , "body_block_name" )
276+ ns = "default"
277+ promise_blocks = set ()
278+ bundle_blocks = set ()
279+ body_blocks = set ()
280+
281+ for child in root_node .children :
282+ if child .type == "body_block" :
283+ name_node = next (
284+ (c for c in child .named_children if c .type == "body_block_name" ),
285+ None ,
286+ )
287+ ns_attr = next (
288+ (
289+ c
290+ for c in _find_node_type (filename , lines , child , "attribute_name" )
291+ if _text (c ) == "namespace"
292+ ),
293+ None ,
294+ )
295+ if ns_attr is not None :
296+ ns = _text (ns_attr .next_named_sibling ).strip ("\" '" )
297+ elif name_node is not None :
298+ body_blocks .add (_State .qualify (_text (name_node ), ns ))
299+ elif child .type == "bundle_block" :
300+ name_node = next (
301+ (c for c in child .named_children if c .type == "bundle_block_name" ),
302+ None ,
303+ )
304+ if name_node is not None :
305+ bundle_blocks .add (_State .qualify (_text (name_node ), ns ))
306+ elif child .type == "promise_block" :
307+ name_node = next (
308+ (c for c in child .named_children if c .type == "promise_block_name" ),
309+ None ,
310+ )
311+ if name_node is not None :
312+ promise_blocks .add (_text (name_node ))
249313
250314 return {
251- "custom_promise_types" : { _text ( x ) for x in promise_blocks } ,
252- "all_bundle_names" : { _text ( x ) for x in bundle_blocks } ,
253- "all_body_names" : { _text ( x ) for x in body_blocks } ,
315+ "custom_promise_types" : promise_blocks ,
316+ "all_bundle_names" : bundle_blocks ,
317+ "all_body_names" : body_blocks ,
254318 }
255319
256320
0 commit comments