1
+ import itertools
1
2
import json
3
+ import re
2
4
from pathlib import Path
3
5
4
6
from django .conf import settings
@@ -24,28 +26,32 @@ def parse_root_package(package_json):
24
26
url = mod
25
27
if mod [0 ] in ["." , "/" ]:
26
28
# 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
32
32
33
33
for dep_name , dep_version in package_json .get ("dependencies" , {}).items ():
34
34
yield from parse_package_json (settings .BASE_DIR / "node_modules" / dep_name )
35
35
36
36
37
- def get_static_from_abs_path (path : Path ):
37
+ def get_static_from_abs_path (mod : str , path : Path ):
38
38
for finder in get_finders ():
39
39
for storage in finder .storages .values ():
40
40
try :
41
41
rel_path = path .relative_to (Path (storage .location ).resolve ())
42
42
except ValueError :
43
43
pass
44
44
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 ))
49
55
50
56
51
57
# There is a long history how ESM is supported in Node.js
@@ -71,6 +77,18 @@ def cast_exports(package_json):
71
77
return exports
72
78
73
79
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
+
74
92
def parse_package_json (path : Path = None ):
75
93
"""Parse a project main package.json and return a dict of importmap entries."""
76
94
with (path / "package.json" ).open () as f :
@@ -80,18 +98,19 @@ def parse_package_json(path: Path = None):
80
98
exports = cast_exports (package_json )
81
99
82
100
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 ))
87
102
88
103
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
+ )
90
109
)
91
110
92
- if (path / "node_modules" ).exists ():
93
- node_modules = path / "node_modules"
94
- else :
95
- node_modules = path / "/" .join (".." for _ in Path (name ).parts )
96
111
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