From 9bb6169a1cba900fa79d63119696efe265762083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 17 May 2024 12:36:06 +0000 Subject: [PATCH] 8317621: --add-script should support JavaScript modules Reviewed-by: jjg --- .../formats/html/HtmlConfiguration.java | 47 +++++- .../doclets/formats/html/markup/Head.java | 23 ++- .../TestJavaScriptModules.java | 149 ++++++++++++++++++ 3 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testJavaScriptModules/TestJavaScriptModules.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java index d3d46c3c3b8..649687e19a2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java @@ -25,8 +25,11 @@ package jdk.javadoc.internal.doclets.formats.html; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.time.ZonedDateTime; @@ -41,6 +44,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.PackageElement; @@ -64,6 +68,7 @@ import jdk.javadoc.internal.doclets.toolkit.Messages; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; +import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.NewAPIBuilder; @@ -198,6 +203,18 @@ public class HtmlConfiguration extends BaseConfiguration { */ private final Set containingPackagesSeen; + /** + * List of additional JavaScript files + */ + private List additionalScripts; + + /** + * Record for JavaScript file and module flag. + * @param path file path + * @param isModule module flag + */ + public record JavaScriptFile(DocPath path, boolean isModule) {} + /** * Constructs the full configuration needed by the doclet, including * the format-specific part, defined in this class, and the format-independent @@ -316,6 +333,9 @@ public class HtmlConfiguration extends BaseConfiguration { } } } + additionalScripts = options.additionalScripts().stream() + .map(this::detectJSModule) + .collect(Collectors.toList()); if (options.createIndex()) { indexBuilder = new HtmlIndexBuilder(this); } @@ -326,6 +346,26 @@ public class HtmlConfiguration extends BaseConfiguration { return true; } + private JavaScriptFile detectJSModule(String fileName) { + DocFile file = DocFile.createFileForInput(this, fileName); + boolean isModule = fileName.toLowerCase(Locale.ROOT).endsWith(".mjs"); + if (!isModule) { + // Regex to detect JavaScript modules + Pattern modulePattern = Pattern.compile(""" + (?:^|[;}])\\s*(?:\ + import\\s*["']|\ + import[\\s{*][^()]*from\\s*["']|\ + export(?:\\s+(?:let|const|function|class|var|default|async)|\\s*[{*]))"""); + try (InputStream in = file.openInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + isModule = reader.lines().anyMatch(s -> modulePattern.matcher(s).find()); + } catch (DocFileIOException | IOException e) { + // Errors are handled when copying resources + } + } + return new JavaScriptFile(DocPath.create(file.getName()), isModule); + } + /** * {@return the date to be recorded in generated files} */ @@ -421,11 +461,8 @@ public class HtmlConfiguration extends BaseConfiguration { .collect(Collectors.toCollection(ArrayList::new)); } - public List getAdditionalScripts() { - return options.additionalScripts().stream() - .map(sf -> DocFile.createFileForInput(this, sf)) - .map(file -> DocPath.create(file.getName())) - .collect(Collectors.toCollection(ArrayList::new)); + public List getAdditionalScripts() { + return additionalScripts; } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 77d09c7226e..c4a223a94c7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Locale; import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; @@ -60,7 +61,7 @@ public class Head extends Content { private Script mainBodyScript; private final List""", + """ + """, + """ + """, + """ + """, + """ + """, + """ + """, + """ + """, + """ + """, + """ + """, + """ + """, + """ + """, + """ + """); + } +}