@@ -127,9 +127,10 @@ private void handleAsset(String npmModule, String npmAsset) {
127127 File npmModuleDir = new File (options .getNodeModulesFolder (), npmModule );
128128
129129 List <Path > paths = collectFiles (npmModuleDir .toPath (), rule .copyRule );
130+ Path basePath = getBasePath (npmModuleDir .toPath (), rule .copyRule );
130131
131132 paths .stream ().map (Path ::toFile ).forEach (file -> {
132- copyFileToTarget (file , new File ( staticOutput , rule . targetFolder ) );
133+ copyFileToTarget (file , rule , basePath );
133134 });
134135 }
135136
@@ -144,8 +145,13 @@ private Rule getRule(String npmAsset, String npmModule) {
144145 return rule ;
145146 }
146147
147- private void copyFileToTarget (File file , File targetFolder ) {
148- File destFile = new File (targetFolder , file .getName ());
148+ private void copyFileToTarget (File file , Rule copyRule , Path basePath ) {
149+ File baseDestinationFolder = new File (staticOutput ,
150+ copyRule .targetFolder );
151+
152+ Path relativePath = basePath .relativize (file .toPath ());
153+ File destFile = new File (baseDestinationFolder ,
154+ relativePath .toString ());
149155 // Copy file to a target path, if target file doesn't exist
150156 // or if file to copy is newer.
151157 if (!destFile .exists ()
@@ -162,6 +168,36 @@ private void copyFileToTarget(File file, File targetFolder) {
162168 }
163169 }
164170
171+ private Path getBasePath (Path npmModuleDir , String copyRule ) {
172+ // Extract the static part of the copy rule (before any wildcards)
173+ String basePathStr = copyRule ;
174+
175+ // Remove leading slashes
176+ if (basePathStr .startsWith ("/" )) {
177+ basePathStr = basePathStr .substring (1 );
178+ }
179+
180+ int wildcardIndex = -1 ;
181+ if (basePathStr .contains ("*" )) {
182+ wildcardIndex = basePathStr .indexOf ('*' );
183+ } else if (basePathStr .contains ("?" )) {
184+ wildcardIndex = basePathStr .indexOf ('?' );
185+ }
186+
187+ if (wildcardIndex != -1 ) {
188+ basePathStr = basePathStr .substring (0 , wildcardIndex );
189+ // Remove trailing slash or incomplete path segment
190+ int lastSlash = basePathStr .lastIndexOf ('/' );
191+ if (lastSlash != -1 ) {
192+ // Resolve the base path relative to npmModuleDir
193+ return npmModuleDir
194+ .resolve (basePathStr .substring (0 , lastSlash ));
195+ }
196+ }
197+
198+ return npmModuleDir ;
199+ }
200+
165201 private List <Path > collectFiles (Path basePath , String matcherPattern ) {
166202 final List <Path > filePaths = new ArrayList <>();
167203 if (!basePath .toFile ().exists ()) {
0 commit comments