@@ -709,19 +709,31 @@ def parse_plain_file(
709709 )
710710
711711
712+ @dataclass
713+ class RequiredModule :
714+ """A required module as parsed by the requires walk; validated once the top module is complete."""
715+
716+ parse_result : PlainFileParseResult
717+ # Definitions exported to this module by the modules it requires.
718+ ancestor_exported_definitions : list [mistletoe .block_token .token ]
719+ code_variables : dict
720+ # Definitions this module exports to the modules that require it.
721+ exported_definitions : list [mistletoe .block_token .token ]
722+
723+
712724def process_required_modules (
713725 required_modules : list [str ],
714726 template_dirs : list [str ],
715727 all_required_modules : list [str ],
716728 modules_trace : list [str ],
717- chain : list [tuple [ str , dict ] ],
718- module_exports : dict [str , list [ mistletoe . block_token . token ] ],
729+ walk_order : list [str ],
730+ required : dict [str , RequiredModule ],
719731) -> list [mistletoe .block_token .token ]:
720- """Parse and fully validate every required module, deepest first.
732+ """Parse every required module, deepest first, without validating it .
721733
722- Appends ``( module name, marshalled plain source tree)`` to ``chain `` for each module not already in it ,
723- records each module's exported definitions in ``module_exports ``, and returns the exported definitions
724- of the directly required modules.
734+ Appends each module name to ``walk_order `` the first time it is reached (deepest ancestors first) ,
735+ records its parse result in ``required ``, and returns the exported definitions of the directly
736+ required modules.
725737 """
726738 exported_definitions = list [mistletoe .block_token .token ]()
727739 for module_name in required_modules :
@@ -730,7 +742,7 @@ def process_required_modules(
730742
731743 if len (all_required_modules ) > 0 and module_name == all_required_modules [- 1 ]:
732744 # Already processed as an earlier entry; its exports are still visible to this module.
733- exported_definitions .extend (module_exports [module_name ])
745+ exported_definitions .extend (required [module_name ]. exported_definitions )
734746 continue
735747
736748 code_variables : dict = {}
@@ -753,8 +765,8 @@ def process_required_modules(
753765 template_dirs ,
754766 all_required_modules ,
755767 modules_trace + [module_name ],
756- chain ,
757- module_exports ,
768+ walk_order ,
769+ required ,
758770 )
759771
760772 own_exported_definitions = list [mistletoe .block_token .token ]()
@@ -770,20 +782,37 @@ def process_required_modules(
770782 exported_concept , plain_file_parse_result .plain_source , renderer
771783 )
772784 )
773- module_exports [module_name ] = own_exported_definitions
785+ required [module_name ] = RequiredModule (
786+ plain_file_parse_result , ancestor_exported_definitions , code_variables , own_exported_definitions
787+ )
774788 exported_definitions .extend (own_exported_definitions )
775789
776- marshalled_plain_source = validate_and_marshall_module (
777- plain_file_parse_result , module_name , ancestor_exported_definitions , code_variables , template_dirs
778- )
779- if module_name not in (chain_module_name for chain_module_name , _ in chain ):
780- chain .append ((module_name , marshalled_plain_source ))
790+ if module_name not in walk_order :
791+ walk_order .append (module_name )
781792
782793 all_required_modules .append (module_name )
783794
784795 return exported_definitions
785796
786797
798+ def validate_required_modules (
799+ required_modules : list [str ],
800+ required : dict [str , RequiredModule ],
801+ template_dirs : list [str ],
802+ trees : dict [str , dict ],
803+ ) -> None :
804+ """Validate recorded required modules as codeplain does: top-down, in listed order, each module once."""
805+ for module_name in required_modules :
806+ if module_name in trees :
807+ continue
808+
809+ module = required [module_name ]
810+ trees [module_name ] = validate_and_marshall_module (
811+ module .parse_result , module_name , module .ancestor_exported_definitions , module .code_variables , template_dirs
812+ )
813+ validate_required_modules (module .parse_result .required_modules , required , template_dirs , trees )
814+
815+
787816def process_exported_definitions (plain_source : dict , exported_definitions : list [mistletoe .block_token .token ]) -> None :
788817 if len (exported_definitions ) == 0 :
789818 return
@@ -908,20 +937,29 @@ def _parse_module(
908937 modules_trace = [],
909938 )
910939
911- chain : list [tuple [str , dict ]] = []
940+ # The order below is codeplain's: the top module's structure, the requires walk, the top module's
941+ # remaining checks, then every required module top-down.
942+ validate_module_structure (plain_file_parse_result , module_name )
943+
944+ walk_order : list [str ] = []
945+ required : dict [str , RequiredModule ] = {}
912946 exported_definitions = process_required_modules (
913947 plain_file_parse_result .required_modules ,
914948 template_dirs = template_dirs ,
915949 all_required_modules = [],
916950 modules_trace = [],
917- chain = chain ,
918- module_exports = {} ,
951+ walk_order = walk_order ,
952+ required = required ,
919953 )
920954
921- marshalled_plain_source = validate_and_marshall_module (
955+ marshalled_plain_source = validate_and_build_module_tree (
922956 plain_file_parse_result , module_name , exported_definitions , code_variables , template_dirs
923957 )
924958
959+ trees : dict [str , dict ] = {}
960+ validate_required_modules (plain_file_parse_result .required_modules , required , template_dirs , trees )
961+ chain = [(chain_module_name , trees [chain_module_name ]) for chain_module_name in walk_order ]
962+
925963 return module_name , marshalled_plain_source , plain_file_parse_result .required_modules , chain
926964
927965
0 commit comments