1+ import itertools
12import json
3+ import re
24from pathlib import Path
35
46from django .conf import settings
@@ -24,28 +26,32 @@ def parse_root_package(package_json):
2426 url = mod
2527 if mod [0 ] in ["." , "/" ]:
2628 # local file
27- if mod .endswith ("/*" ):
28- mod = mod [:- 1 ]
29- module_name = module_name [:- 1 ]
30- url = get_static_from_abs_path (settings .BASE_DIR / mod )
31- yield module_name , url
29+ yield from get_static_from_abs_path (module_name , settings .BASE_DIR / mod )
30+ else :
31+ yield module_name , url
3232
3333 for dep_name , dep_version in package_json .get ("dependencies" , {}).items ():
3434 yield from parse_package_json (settings .BASE_DIR / "node_modules" / dep_name )
3535
3636
37- def get_static_from_abs_path (path : Path ):
37+ def get_static_from_abs_path (mod : str , path : Path ):
3838 for finder in get_finders ():
3939 for storage in finder .storages .values ():
4040 try :
4141 rel_path = path .relative_to (Path (storage .location ).resolve ())
4242 except ValueError :
4343 pass
4444 else :
45- if path .is_dir ():
46- return settings .STATIC_URL + str (rel_path ) + "/"
47- return staticfiles_storage .url (str (rel_path ))
48- raise ValueError (f"Could not find { path } in staticfiles" )
45+ if "*" in mod :
46+ for match in Path (storage .location ).rglob (
47+ str (rel_path ).replace ("*" , "**/*" )
48+ ):
49+ sp = str (match .relative_to (Path (storage .location ).resolve ()))
50+ pattern = re .escape (str (rel_path )).replace (r"\*" , r"(.*)" )
51+ bit = re .match (pattern , sp ).group (1 )
52+ yield mod .replace ("*" , bit ), staticfiles_storage .url (sp )
53+ else :
54+ yield mod , staticfiles_storage .url (str (rel_path ))
4955
5056
5157# There is a long history how ESM is supported in Node.js
@@ -71,6 +77,18 @@ def cast_exports(package_json):
7177 return exports
7278
7379
80+ def find_default_key (module ):
81+ try :
82+ yield module ["default" ]
83+ except TypeError :
84+ if isinstance (module , list ):
85+ yield from itertools .chain (* (find_default_key (i ) for i in module ))
86+ else :
87+ yield module
88+ except KeyError :
89+ yield from find_default_key (module ["import" ])
90+
91+
7492def parse_package_json (path : Path = None ):
7593 """Parse a project main package.json and return a dict of importmap entries."""
7694 with (path / "package.json" ).open () as f :
@@ -80,18 +98,19 @@ def parse_package_json(path: Path = None):
8098 exports = cast_exports (package_json )
8199
82100 for module_name , module in exports .items ():
83- try :
84- mod = module ["default" ]
85- except TypeError :
86- mod = module
101+ module = next (find_default_key (module ))
87102
88103 yield str (Path (name ) / module_name ), staticfiles_storage .url (
89- str ((path / mod ).resolve ().relative_to (settings .BASE_DIR / "node_modules" ))
104+ str (
105+ (path / module )
106+ .resolve ()
107+ .relative_to (settings .BASE_DIR / "node_modules" )
108+ )
90109 )
91110
92- if (path / "node_modules" ).exists ():
93- node_modules = path / "node_modules"
94- else :
95- node_modules = path / "/" .join (".." for _ in Path (name ).parts )
96111 for dep_name , dep_version in dependencies .items ():
97- yield from parse_package_json (node_modules / dep_name )
112+ dep_path = path
113+ while not (dep_path / "node_modules" / dep_name ).exists ():
114+ dep_path /= ".."
115+
116+ yield from parse_package_json ((dep_path / "node_modules" / dep_name ).resolve ())
0 commit comments