Skip to content

Commit cfa768d

Browse files
authored
fix: avoid infinite recursion on imported directories (#15596)
Fixes #15595
1 parent 3946b30 commit cfa768d

File tree

2 files changed

+77
-4
lines changed

2 files changed

+77
-4
lines changed

flow-server/src/main/java/com/vaadin/flow/server/frontend/AbstractUpdateImports.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,11 @@ private boolean isFile(File base, String... path) {
494494
return getFile(base, path).isFile();
495495
}
496496

497+
private boolean isFileOrDirectory(File base, String... path) {
498+
File file = getFile(base, path);
499+
return file.isFile() || file.isDirectory();
500+
}
501+
497502
private boolean addCssLines(Collection<String> lines, CssData cssData,
498503
int i) {
499504
String cssFile = resolveResource(cssData.getValue());
@@ -560,7 +565,8 @@ private boolean hasMetaInfResource(String resource) {
560565
private String toValidBrowserImport(String jsImport) {
561566
if (jsImport.startsWith(NodeUpdater.GENERATED_PREFIX)) {
562567
return generatedResourcePathIntoRelativePath(jsImport);
563-
} else if (isFile(options.getFrontendDirectory(), jsImport)) {
568+
} else if (isFileOrDirectory(options.getFrontendDirectory(),
569+
jsImport)) {
564570
if (!jsImport.startsWith("./")) {
565571
getLogger().warn(
566572
"Use the './' prefix for files in the '{}' folder: '{}', please update your annotations.",
@@ -633,7 +639,11 @@ private void handleImports(String path, AbstractTheme theme,
633639
return;
634640
}
635641
Path filePath = file.toPath();
636-
visitedImports.add(filePath.normalize().toString().replace("\\", "/"));
642+
String normalizedPath = filePath.normalize().toString().replace("\\",
643+
"/");
644+
if (!visitedImports.add(normalizedPath)) {
645+
return;
646+
}
637647
try {
638648
visitImportsRecursively(filePath, path, theme, imports,
639649
visitedImports);
@@ -659,8 +669,13 @@ private void handleImports(String path, AbstractTheme theme,
659669
*/
660670
private String resolve(String importedPath, Path moduleFile, String path) {
661671
String pathPrefix = moduleFile.toString();
662-
pathPrefix = pathPrefix.substring(0,
663-
pathPrefix.length() - path.length());
672+
int pathLength = path.length();
673+
// path may have been resolved as `path/index.js`, if path points to a
674+
// directory
675+
if (!moduleFile.endsWith(path) && moduleFile.endsWith("index.js")) {
676+
pathLength += 9;
677+
}
678+
pathPrefix = pathPrefix.substring(0, pathPrefix.length() - pathLength);
664679
try {
665680
String resolvedPath = moduleFile.getParent().resolve(importedPath)
666681
.toString();

flow-server/src/test/java/com/vaadin/flow/server/frontend/UpdateThemedImportsTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,64 @@ public void noDuplicateImportEntryIsWrittenIntoImportsFile()
188188
count);
189189
}
190190

191+
@Test
192+
public void directoryImportEntryIsResolvedAsIndexJS() throws Exception {
193+
194+
createImport("./src/directory/index.js",
195+
"import { xx } from './sub1.js';");
196+
createImport("./src/directory/sub1.js", "");
197+
createImport("./src/main-template.js",
198+
"import 'xx' from './directory';");
199+
200+
// create themed modules
201+
createImport("./theme/myTheme/directory/index.js", "");
202+
createImport("./theme/myTheme/directory/sub1.js", "");
203+
createImport("./theme/myTheme/main-template.js", "");
204+
205+
updater.execute();
206+
207+
String content = FileUtils.readFileToString(importsFile,
208+
Charset.defaultCharset());
209+
MatcherAssert.assertThat(content, CoreMatchers.allOf(
210+
CoreMatchers.containsString(
211+
"import 'Frontend/theme/myTheme/main-template.js';"),
212+
CoreMatchers.containsString(
213+
"import 'Frontend/theme/myTheme/directory';"),
214+
CoreMatchers.containsString(
215+
"import 'Frontend/theme/myTheme/directory/sub1.js';")));
216+
}
217+
218+
@Test
219+
public void directoryImportEntry_avoidRecursion() throws Exception {
220+
221+
createImport("./src/directory/index.js",
222+
"import { xx } from '../import2.js';");
223+
createImport("./src/import1.js", "import { xx } from './directory/';");
224+
createImport("./src/import2.js", "import 'xx' from './import1.js';");
225+
createImport("./src/main-template.js",
226+
"import 'xx' from './directory';");
227+
228+
// create themed modules
229+
createImport("./theme/myTheme/directory", "");
230+
createImport("./theme/myTheme/import1.js", "");
231+
createImport("./theme/myTheme/import2.js", "");
232+
createImport("./theme/myTheme/main-template.js", "");
233+
234+
updater.execute();
235+
236+
String content = FileUtils.readFileToString(importsFile,
237+
Charset.defaultCharset());
238+
MatcherAssert.assertThat(content, CoreMatchers.allOf(
239+
CoreMatchers.containsString(
240+
"import 'Frontend/theme/myTheme/main-template.js';"),
241+
CoreMatchers.containsString(
242+
"import 'Frontend/theme/myTheme/directory';"),
243+
CoreMatchers.containsString(
244+
"import 'Frontend/theme/myTheme/import1.js';"),
245+
CoreMatchers.containsString(
246+
"import 'Frontend/theme/myTheme/import2.js';")));
247+
}
248+
191249
private void createImport(String path, String content) throws IOException {
192250
File newFile = resolveImportFile(frontendDirectory, nodeModulesPath,
193251
path);

0 commit comments

Comments
 (0)