diff --git a/.gitignore b/.gitignore
index a4beeeac..2cb4fd36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ target/
*.iml
**/src/main/resources/**.tgz
/nbactions.xml
+**node_modules**
\ No newline at end of file
diff --git a/bundle-original/pom.xml b/bundle-original/pom.xml
deleted file mode 100644
index 9b1f1431..00000000
--- a/bundle-original/pom.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
- 4.0.0
-
-
- io.mvnpm
- esbuild-java-parent
- 999-SNAPSHOT
-
- esbuild-java-bundle-original
- Esbuild wrapper for Java bundled with original binaries
-
- 0.25.9
-
-
-
- io.mvnpm
- esbuild-java
- ${project.version}
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
-
- org.hamcrest
- hamcrest-all
- 1.3
- test
-
-
-
-
-
- src/main/resources
- false
-
-
- src/main/resources-filtered
- true
-
-
-
-
- net.revelc.code.formatter
- formatter-maven-plugin
-
-
- net.revelc.code
- impsort-maven-plugin
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
- ${maven-antrun-plugin.version}
-
-
- download
- generate-resources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- run
-
-
-
-
-
-
-
-
diff --git a/bundle-original/src/main/resources-filtered/esbuild-java-version.properties b/bundle-original/src/main/resources-filtered/esbuild-java-version.properties
deleted file mode 100644
index 1254bac2..00000000
--- a/bundle-original/src/main/resources-filtered/esbuild-java-version.properties
+++ /dev/null
@@ -1 +0,0 @@
-esbuild.version=${esbuild.version}
\ No newline at end of file
diff --git a/bundle-original/src/test/java/io/mvnpm/esbuild/resolve/BundleResolverTest.java b/bundle-original/src/test/java/io/mvnpm/esbuild/resolve/BundleResolverTest.java
deleted file mode 100644
index 04b4335c..00000000
--- a/bundle-original/src/test/java/io/mvnpm/esbuild/resolve/BundleResolverTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.mvnpm.esbuild.resolve;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.IOException;
-import java.nio.file.Path;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import io.mvnpm.esbuild.Bundler;
-
-public class BundleResolverTest extends BundleTester {
-
- public static final Resolver THROWING_RESOLVER = version -> {
- throw new RuntimeException("Should not call this");
- };
-
- @BeforeAll
- public static void cleanUp() throws IOException {
- cleanUpDefault();
- }
-
- @Test
- public void resolve() throws IOException {
- // when
- final Path resolve = new BundledResolver(THROWING_RESOLVER).resolve(Bundler.ESBUILD_EMBEDDED_VERSION);
-
- assertFalse(Bundler.ESBUILD_EMBEDDED_VERSION.contains("mvnpm"));
-
- // then
- assertTrue(resolve.toFile().exists());
- }
-}
diff --git a/bundle-scss/pom.xml b/bundle-scss/pom.xml
deleted file mode 100644
index b8a4c625..00000000
--- a/bundle-scss/pom.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
- 4.0.0
-
-
- io.mvnpm
- esbuild-java-parent
- 999-SNAPSHOT
-
- esbuild-java-bundle-scss
- Esbuild wrapper for Java bundled with mvnpm scss binaries
- jar
-
-
- io.mvnpm
- esbuild-java
- ${project.version}
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
-
- org.hamcrest
- hamcrest-all
- 1.3
- test
-
-
-
-
-
- src/main/resources
- false
-
-
- src/main/resources-filtered
- true
-
-
-
-
- net.revelc.code.formatter
- formatter-maven-plugin
-
-
- net.revelc.code
- impsort-maven-plugin
-
-
- org.apache.maven.plugins
- maven-antrun-plugin
- ${maven-antrun-plugin.version}
-
-
- download
- generate-resources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- run
-
-
-
-
-
-
-
-
diff --git a/bundle-scss/src/main/resources-filtered/esbuild-java-version.properties b/bundle-scss/src/main/resources-filtered/esbuild-java-version.properties
deleted file mode 100644
index 2780172a..00000000
--- a/bundle-scss/src/main/resources-filtered/esbuild-java-version.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-esbuild.mvnpm-build.version=${esbuild.mvnpm-build.version}
-esbuild.version=${esbuild.version}
\ No newline at end of file
diff --git a/bundle-scss/src/test/java/io/mvnpm/esbuild/resolve/BundleResolverTest.java b/bundle-scss/src/test/java/io/mvnpm/esbuild/resolve/BundleResolverTest.java
deleted file mode 100644
index f76ff8ea..00000000
--- a/bundle-scss/src/test/java/io/mvnpm/esbuild/resolve/BundleResolverTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.mvnpm.esbuild.resolve;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.IOException;
-import java.nio.file.Path;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import io.mvnpm.esbuild.Bundler;
-
-public class BundleResolverTest extends BundleTester {
-
- public static final Resolver THROWING_RESOLVER = version -> {
- throw new RuntimeException("Should not call this");
- };
-
- @BeforeAll
- public static void cleanUp() throws IOException {
- cleanUpDefault();
- }
-
- @Test
- public void resolve() throws IOException {
- // when
- final Path resolve = new BundledResolver(THROWING_RESOLVER).resolve(Bundler.ESBUILD_EMBEDDED_VERSION);
- assertTrue(Bundler.ESBUILD_EMBEDDED_VERSION.contains("mvnpm"));
- // then
- assertTrue(resolve.toFile().exists());
- }
-}
diff --git a/bundle-scss/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java b/bundle-scss/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
deleted file mode 100644
index 9926effa..00000000
--- a/bundle-scss/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.mvnpm.esbuild.resolve;
-
-import java.io.IOException;
-
-import io.mvnpm.esbuild.Bundler;
-import io.mvnpm.esbuild.util.PathUtils;
-
-public abstract class BundleTester {
-
- public static void cleanUp(String version) throws IOException {
- PathUtils.deleteRecursive(Resolvers.getLocation(version));
- }
-
- public static void cleanUpDefault() throws IOException {
- cleanUp(Bundler.ESBUILD_EMBEDDED_VERSION);
- }
-}
diff --git a/core/pom.xml b/core/pom.xml
index b8131b65..fc7c8f51 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -1,25 +1,39 @@
4.0.0
-
io.mvnpm
esbuild-java-parent
999-SNAPSHOT
esbuild-java
- Esbuild wrapper for Java
-
+ Esbuild Java
Small wrapper around esbuild to be able to use it in Java
-
+
+ 0.25.10
+ 5.1.2
+ 0.4.2
+ 5.0.0
+
-
-
+
+ com.caoccao.javet
+ javet
+ ${javet.version}
+
+
+
+ org.mvnpm
+ esbuild
+ ${esbuild.version}
+
+
io.mvnpm
importmap
1.0.10
+
org.apache.commons
commons-compress
@@ -28,27 +42,12 @@
com.fasterxml.jackson.core
jackson-databind
-
-
-
- org.junit.jupiter
- junit-jupiter-engine
- test
-
-
- org.hamcrest
- hamcrest-all
- 1.3
- test
-
-
-
src/main/resources
- false
+ true
src/main/resources-filtered
@@ -79,8 +78,129 @@
net.revelc.code
impsort-maven-plugin
-
-
+
+
+ darwin-arm64
+
+
+ aarch64
+ mac
+
+
+
+
+ org.mvnpm.at.esbuild
+ darwin-arm64
+ ${esbuild.version}
+
+
+ com.caoccao.javet
+ javet-node-macos-arm64
+ ${javet.version}
+
+
+
+
+ darwin-x64
+
+
+ x86_64
+ mac
+
+
+
+
+ org.mvnpm.at.esbuild
+ darwin-x64
+ ${esbuild.version}
+
+
+ com.caoccao.javet
+ javet-node-macos-x86_64
+ ${javet.version}
+
+
+
+
+ linux-x64
+
+
+ x86_64
+ unix
+
+
+
+
+ org.mvnpm.at.esbuild
+ linux-x64
+ ${esbuild.version}
+
+
+ com.caoccao.javet
+ javet-node-linux-x86_64
+ ${javet.version}
+
+
+
+
+ linux-arm
+
+
+ aarch64
+ unix
+
+
+
+
+ org.mvnpm.at.esbuild
+ linux-arm
+ ${esbuild.version}
+
+
+ com.caoccao.javet
+ javet-node-linux-arm64
+ ${javet.version}
+
+
+
+
+ windows-x64
+
+
+ x86_64
+ windows
+
+
+
+
+ org.mvnpm.at.esbuild
+ win32-x64
+ ${esbuild.version}
+
+
+ com.caoccao.javet
+ javet-node-windows-x86_64
+ ${javet.version}
+
+
+
+
+ windows-ia32
+
+
+ x86
+ windows
+
+
+
+
+ org.mvnpm.at.esbuild
+ win32-ia32
+ ${esbuild.version}
+
+
+
+
diff --git a/core/src/main/java/io/mvnpm/esbuild/BuildEventListener.java b/core/src/main/java/io/mvnpm/esbuild/BuildEventListener.java
deleted file mode 100644
index 0b73fd5b..00000000
--- a/core/src/main/java/io/mvnpm/esbuild/BuildEventListener.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.mvnpm.esbuild;
-
-import io.mvnpm.esbuild.model.WatchBuildResult;
-
-public interface BuildEventListener {
-
- void onBuild(WatchBuildResult result);
-
-}
diff --git a/core/src/main/java/io/mvnpm/esbuild/BundleException.java b/core/src/main/java/io/mvnpm/esbuild/BundleException.java
index aabb7071..16eb6ae2 100644
--- a/core/src/main/java/io/mvnpm/esbuild/BundleException.java
+++ b/core/src/main/java/io/mvnpm/esbuild/BundleException.java
@@ -2,19 +2,35 @@
public class BundleException extends RuntimeException {
- private final String output;
+ private final String details;
- public BundleException(String message, String output) {
+ /**
+ * Creates a BundleException with a message and optional details.
+ *
+ * @param message The main exception message.
+ * @param details Additional details (can be null or empty).
+ */
+ public BundleException(String message, String details) {
super(message);
- this.output = output;
+ this.details = details != null ? details : "";
+ }
+
+ /**
+ * Convenience constructor when there are no extra details.
+ */
+ public BundleException(String message) {
+ this(message, "");
}
@Override
public String getMessage() {
- return super.getMessage() + ": \n" + output;
+ if (details.isEmpty()) {
+ return super.getMessage();
+ }
+ return super.getMessage() + ":\n" + details;
}
- public String output() {
- return output;
+ public String details() {
+ return details;
}
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/Bundler.java b/core/src/main/java/io/mvnpm/esbuild/Bundler.java
index 9e76cff4..c4cb9061 100644
--- a/core/src/main/java/io/mvnpm/esbuild/Bundler.java
+++ b/core/src/main/java/io/mvnpm/esbuild/Bundler.java
@@ -1,5 +1,6 @@
package io.mvnpm.esbuild;
+import static io.mvnpm.esbuild.script.ScriptRunner.getOutDir;
import static io.mvnpm.esbuild.util.PathUtils.deleteRecursive;
import static java.util.Objects.requireNonNull;
@@ -7,13 +8,15 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
+import io.mvnpm.esbuild.install.EsBuildDeps;
import io.mvnpm.esbuild.install.WebDepsInstaller;
import io.mvnpm.esbuild.model.*;
-import io.mvnpm.esbuild.resolve.Resolver;
+import io.mvnpm.esbuild.script.ScriptRunner;
public class Bundler {
private static final Logger logger = Logger.getLogger(Bundler.class.getName());
@@ -47,17 +50,30 @@ public static BundleResult bundle(BundleOptions bundleOptions, boolean install)
if (install) {
install(workDir, bundleOptions);
}
- final String out = bundleOptions.esBuildConfig().outdir() != null ? bundleOptions.esBuildConfig().outdir() : "dist";
- final Path dist = workDir.resolve(out);
+ final Path dist = getOutDir(workDir, bundleOptions.esBuildConfig());
final EsBuildConfig esBuildConfig = prepareForBundling(bundleOptions, workDir, dist, false);
- final ExecuteResult executeResult = esBuild(workDir, esBuildConfig);
+ esBuild(workDir, esBuildConfig);
if (!Files.isDirectory(dist)) {
- throw new BundleException("Unexpected Error during bundling", executeResult.output());
+ throw new BundleException("Unexpected Error during bundling");
}
- return new BundleResult(dist, workDir, executeResult);
+ return new BundleResult(dist, workDir);
+ }
+
+ public static DevResult dev(BundleOptions bundleOptions, boolean install)
+ throws IOException {
+ final Path workDir = getWorkDir(bundleOptions);
+ if (install) {
+ install(workDir, bundleOptions);
+ }
+ final Path dist = getOutDir(workDir, bundleOptions.esBuildConfig());
+ final EsBuildConfig esBuildConfig = prepareForBundling(bundleOptions, workDir, dist, true);
+
+ final DevResult devResult = esBuildDev(workDir, esBuildConfig);
+ devResult.process().init();
+ return devResult;
}
private static EsBuildConfig prepareForBundling(BundleOptions bundleOptions, Path workDir, Path dist, boolean watch)
@@ -78,20 +94,6 @@ private static EsBuildConfig prepareForBundling(BundleOptions bundleOptions, Pat
.build();
}
- public static Watch watch(BundleOptions bundleOptions, BuildEventListener eventListener, boolean install)
- throws IOException {
- final Path workDir = getWorkDir(bundleOptions);
- if (install) {
- install(workDir, bundleOptions);
- }
- final String out = bundleOptions.esBuildConfig().outdir() != null ? bundleOptions.esBuildConfig().outdir() : "dist";
- final Path dist = workDir.resolve(out);
- final EsBuildConfig esBuildConfig = prepareForBundling(bundleOptions, workDir, dist, true);
-
- final WatchStartResult r = esBuildWatch(workDir, esBuildConfig, eventListener);
- return new Watch(r.process(), workDir, dist, r.firstBuildResult());
- }
-
private static Path getWorkDir(BundleOptions bundleOptions) throws IOException {
return bundleOptions.workDir() != null ? bundleOptions.workDir()
: Files.createTempDirectory("bundle");
@@ -99,7 +101,9 @@ private static Path getWorkDir(BundleOptions bundleOptions) throws IOException {
public static boolean install(Path workDir, BundleOptions bundleOptions) throws IOException {
final Path nodeModulesDir = getNodeModulesDir(workDir, bundleOptions);
- return WebDepsInstaller.install(nodeModulesDir, bundleOptions.dependencies());
+ final List dependencies = new ArrayList<>(bundleOptions.dependencies());
+ dependencies.addAll(EsBuildDeps.get().deps());
+ return WebDepsInstaller.install(nodeModulesDir, dependencies);
}
protected static Path getNodeModulesDir(Path workDir, BundleOptions bundleOptions) {
@@ -112,21 +116,15 @@ public static void clearDependencies(Path nodeModulesDir) throws IOException {
deleteRecursive(nodeModulesDir);
}
- protected static WatchStartResult esBuildWatch(Path workDir, EsBuildConfig esBuildConfig, BuildEventListener listener)
+ protected static DevResult esBuildDev(Path workDir, EsBuildConfig esBuildConfig)
throws IOException {
- final Execute execute = getExecute(workDir, esBuildConfig);
- return execute.watch(listener);
+ final ScriptRunner scriptRunner = new ScriptRunner(workDir, esBuildConfig);
+ return new DevResult(scriptRunner.dev());
}
- protected static ExecuteResult esBuild(Path workDir, EsBuildConfig esBuildConfig) throws IOException {
- final Execute execute = getExecute(workDir, esBuildConfig);
- return execute.executeAndWait();
+ protected static void esBuild(Path workDir, EsBuildConfig esBuildConfig) throws IOException {
+ final ScriptRunner scriptRunner = new ScriptRunner(workDir, esBuildConfig);
+ scriptRunner.build();
}
- private static Execute getExecute(Path workDir, EsBuildConfig esBuildConfig) throws IOException {
- final String version = esBuildConfig.esBuildVersion() != null ? esBuildConfig.esBuildVersion()
- : Bundler.ESBUILD_EMBEDDED_VERSION;
- final Path esBuildExec = Resolver.create().resolve(version);
- return new Execute(workDir, esBuildExec.toFile(), esBuildConfig);
- }
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/Execute.java b/core/src/main/java/io/mvnpm/esbuild/Execute.java
deleted file mode 100644
index 31f4c4c2..00000000
--- a/core/src/main/java/io/mvnpm/esbuild/Execute.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package io.mvnpm.esbuild;
-
-import java.io.*;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import io.mvnpm.esbuild.model.EsBuildConfig;
-import io.mvnpm.esbuild.model.ExecuteResult;
-import io.mvnpm.esbuild.model.WatchBuildResult;
-import io.mvnpm.esbuild.model.WatchStartResult;
-
-public class Execute {
-
- private static final ExecutorService EXECUTOR_STREAMER = Executors.newSingleThreadExecutor(r -> {
- final Thread t = new Thread(r, "Process stdout streamer");
- t.setDaemon(true);
- return t;
- });
- private static final Logger logger = Logger.getLogger(Execute.class.getName());
-
- private final Path workDir;
- private final File esBuildExec;
- private EsBuildConfig esBuildConfig;
- private String[] args;
-
- public Execute(Path workDir, File esBuildExec, EsBuildConfig esBuildConfig) {
- this.workDir = workDir;
- this.esBuildExec = esBuildExec;
- this.esBuildConfig = esBuildConfig;
- }
-
- public Execute(Path workDir, File esBuildExec, String[] args) {
- this.workDir = workDir;
- this.esBuildExec = esBuildExec;
- this.args = args;
- }
-
- public ExecuteResult executeAndWait() throws IOException {
- final Process process = createProcess(getCommand(), Optional.empty());
- try {
- final int exitCode = process.waitFor();
- final String content = readStream(process.getInputStream());
- final String errors = readStream(process.getErrorStream());
- if (exitCode != 0) {
- throw new BundleException(errors.isEmpty() ? "Unexpected Error during bundling" : errors, content);
- }
- return new ExecuteResult(content);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
- }
- }
-
- public WatchStartResult watch(BuildEventListener listener) throws IOException {
- final Process process = createProcess(getCommand(), Optional.of(listener));
- final ExecutorService executorStreamer = Executors
- .newSingleThreadExecutor(r -> new Thread(r, "Esbuild watch stdout streamer"));
- final ExecutorService executorBuild = Executors
- .newSingleThreadExecutor(r -> new Thread(r, "Esbuild build listeners notify"));
- final AtomicReference result = new AtomicReference<>();
- CountDownLatch latch = new CountDownLatch(1);
- final WatchStartResult.WatchProcess watchProcess = new WatchStartResult.WatchProcess() {
- @Override
- public boolean isAlive() {
- return process.isAlive();
- }
-
- @Override
- public void close() throws IOException {
- process.destroyForcibly();
- executorStreamer.shutdownNow();
- executorBuild.shutdownNow();
- try {
- process.waitFor();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- if (latch.getCount() == 1) {
- latch.countDown();
- }
- }
- };
- try {
- final InputStream processStream = process.getInputStream();
- executorStreamer.execute(new Streamer(executorBuild, process::isAlive, processStream, (r) -> {
- if (latch.getCount() == 1) {
- result.set(r);
- latch.countDown();
- } else {
- listener.onBuild(r);
- }
- }, r -> {
- try {
- if (process.isAlive()) {
- process.destroyForcibly();
- process.waitFor();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- if (latch.getCount() == 1) {
- result.set(r);
- latch.countDown();
- } else if (!r.isSuccess()) {
- listener.onBuild(r);
- }
- }));
- latch.await();
- if (!process.isAlive() && !result.get().isSuccess()) {
- throw result.get().bundleException();
- }
- return new WatchStartResult(result.get(), watchProcess);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- watchProcess.close();
- throw new RuntimeException(e);
- }
- }
-
- private String[] getCommand() {
- String[] command = args != null ? getCommand(args) : getCommand(esBuildConfig);
- if (logger.isLoggable(Level.FINE)) {
- logger.log(Level.FINE, "running esbuild with flags: \n > `{0}`", String.join(" ", command));
- }
- return command;
- }
-
- private String[] getCommand(EsBuildConfig esBuildConfig) {
- String[] params = esBuildConfig.toParams();
- return getCommand(params);
- }
-
- private String[] getCommand(String[] args) {
- List argList = new ArrayList<>(args.length + 1);
- argList.add(esBuildExec.toString());
- argList.addAll(Arrays.asList(args));
-
- return argList.toArray(String[]::new);
- }
-
- public Process createProcess(final String[] command, final Optional listener) throws IOException {
- return new ProcessBuilder().redirectErrorStream(listener.isPresent()).directory(workDir.toFile())
- .command(command).start();
- }
-
- private record Streamer(ExecutorService executorBuild, BooleanSupplier isAlive, InputStream processStream,
- BuildEventListener listener, Consumer onExit) implements Runnable {
-
- @Override
- public void run() {
- final AtomicBoolean hasError = new AtomicBoolean();
- final StringBuilder outputBuilder = new StringBuilder();
- consumeStream(isAlive, processStream, l -> {
- logger.fine(l);
- outputBuilder.append("\n").append(l);
- if (l.contains("build finished")) {
- logger.fine("Build finished!");
- final String output = outputBuilder.toString();
- final boolean error = hasError.getAndSet(false);
- outputBuilder.setLength(0);
- executorBuild.execute(() -> {
- if (!error) {
- listener.onBuild(new WatchBuildResult(output));
- } else {
- listener.onBuild(
- new WatchBuildResult(output, new BundleException("Error during bundling", output)));
- }
- });
- } else if (l.contains("[ERROR]")) {
- hasError.set(true);
- }
- });
- if (!hasError.get()) {
- onExit.accept(new WatchBuildResult(outputBuilder.toString()));
- } else {
- onExit.accept(new WatchBuildResult(outputBuilder.toString(),
- new BundleException("Process exited with error", outputBuilder.toString())));
- }
- }
- }
-
- private static String readStream(InputStream stream) {
- final StringBuilder s = new StringBuilder();
- consumeStream(() -> true, stream, l -> s.append(l).append("\n"));
- return s.toString();
- }
-
- private static void consumeStream(BooleanSupplier stayAlive, InputStream stream, Consumer newLineConsumer) {
- try (
- final InputStreamReader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
- final BufferedReader reader = new BufferedReader(in)) {
- String line;
- while ((line = reader.readLine()) != null) {
- newLineConsumer.accept(line);
- if (!stayAlive.getAsBoolean()) {
- break;
- }
- }
- } catch (IOException e) {
- // ignore
- }
- }
-
-}
diff --git a/core/src/main/java/io/mvnpm/esbuild/Main.java b/core/src/main/java/io/mvnpm/esbuild/Main.java
index 78161dc3..94ce14e3 100644
--- a/core/src/main/java/io/mvnpm/esbuild/Main.java
+++ b/core/src/main/java/io/mvnpm/esbuild/Main.java
@@ -1,33 +1,14 @@
package io.mvnpm.esbuild;
import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
+import java.net.URISyntaxException;
-import io.mvnpm.esbuild.model.ExecuteResult;
-import io.mvnpm.esbuild.resolve.Resolver;
+import io.mvnpm.esbuild.install.EsBuildDeps;
public class Main {
- public static void main(String[] args) throws IOException {
- String workingDirectory = System.getProperty("user.dir");
- final List arguments = new ArrayList<>(Arrays.asList(args));
- final Optional esbuildVersionArgument = arguments.stream().filter(a -> a.startsWith("--esbuildVersion"))
- .findFirst();
- String esbuildVersion = Bundler.ESBUILD_EMBEDDED_VERSION;
- if (esbuildVersionArgument.isPresent()) {
- arguments.remove(esbuildVersionArgument.get());
- final String unParsedEsbuildVersion = esbuildVersionArgument.get();
- esbuildVersion = unParsedEsbuildVersion.split("=")[1];
- }
- final Path esBuildExec = Resolver.create().resolve(esbuildVersion);
- final ExecuteResult executeResult = new Execute(Paths.get(workingDirectory), esBuildExec.toFile(),
- arguments.toArray(new String[] {}))
- .executeAndWait();
- System.out.println(executeResult.output());
+ public static void main(String[] args) throws IOException, URISyntaxException {
+
+ System.out.println(EsBuildDeps.get());
}
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/Watch.java b/core/src/main/java/io/mvnpm/esbuild/Watch.java
deleted file mode 100644
index 81bfd41f..00000000
--- a/core/src/main/java/io/mvnpm/esbuild/Watch.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package io.mvnpm.esbuild;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.List;
-
-import io.mvnpm.esbuild.model.EntryPoint;
-import io.mvnpm.esbuild.model.WatchBuildResult;
-import io.mvnpm.esbuild.model.WatchStartResult;
-
-public class Watch implements Closeable {
-
- private final WatchStartResult.WatchProcess process;
- private final Path workDir;
-
- private final Path dist;
-
- private final WatchBuildResult firstBuildResult;
-
- public Watch(WatchStartResult.WatchProcess process, Path workDir, Path dist, WatchBuildResult firstBuildResult) {
- this.process = process;
- this.workDir = workDir;
- this.dist = dist;
- this.firstBuildResult = firstBuildResult;
- }
-
- public void updateEntries(List entries) throws IOException {
- entries.forEach(entry -> entry.process(workDir));
- }
-
- @Override
- public void close() throws IOException {
- process.close();
- }
-
- public Path workDir() {
- return workDir;
- }
-
- public WatchBuildResult firstBuildResult() {
- return firstBuildResult;
- }
-
- public boolean isAlive() {
- return process.isAlive();
- }
-
- public Path dist() {
- return dist;
- }
-
-}
diff --git a/core/src/main/java/io/mvnpm/esbuild/install/EsBuildDeps.java b/core/src/main/java/io/mvnpm/esbuild/install/EsBuildDeps.java
new file mode 100644
index 00000000..2c51572e
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/install/EsBuildDeps.java
@@ -0,0 +1,79 @@
+package io.mvnpm.esbuild.install;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import io.mvnpm.esbuild.model.WebDependency;
+
+public record EsBuildDeps(List deps, List plugins) {
+
+ private static AtomicReference DEPS = new AtomicReference<>();
+ private static final Pattern GAV_PATTERN = Pattern.compile(".*/(org/mvnpm(?:/[^/]+)*)/([^/]+)/([^/]+)/\\2-\\3\\.jar$");
+
+ public static EsBuildDeps get() {
+ return DEPS.updateAndGet(c -> {
+ if (c == null) {
+ c = fromClasspath();
+ }
+ return c;
+ });
+ }
+
+ private static EsBuildDeps fromClasspath() {
+ String classpath = System.getProperty("java.class.path");
+ String[] entries = classpath.split(File.pathSeparator);
+ final List plugins = new ArrayList<>();
+ final List deps = Arrays.stream(entries)
+ .map(Paths::get)
+ .map(path -> {
+ final GAV gav = extractGav(path);
+ if (gav == null) {
+ return null;
+ }
+ final String gavString = gav.toString();
+ final Optional type = WebDependency.WebDependencyType
+ .resolveType(gavString);
+ if (type.isEmpty()) {
+ return null;
+ }
+ if (gav.artifactId.matches("^esbuild-[a-z]+-plugin$")) {
+ plugins.add(gav.artifactId);
+ }
+ return WebDependency.of(gavString, path, type.get());
+ })
+ .filter(Objects::nonNull) // only keep dependencies with recognized type
+ .collect(Collectors.toList());
+ return new EsBuildDeps(deps, plugins);
+ }
+
+ private static GAV extractGav(Path jarPath) {
+ String path = jarPath.toString().replace("\\", "/"); // normalize for Windows
+ Matcher matcher = GAV_PATTERN.matcher(path);
+ if (!matcher.matches()) {
+ return null;
+ }
+
+ String groupId = matcher.group(1).replace("/", ".");
+ String artifactId = matcher.group(2);
+ String version = matcher.group(3);
+ return new GAV(groupId, artifactId, version);
+ }
+
+ private record GAV(String groupId, String artifactId, String version) {
+ @Override
+ public String toString() {
+ return groupId + ":" + artifactId + ":" + version;
+ }
+ }
+
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/BundleResult.java b/core/src/main/java/io/mvnpm/esbuild/model/BundleResult.java
index ae2b23c1..032a3b9a 100644
--- a/core/src/main/java/io/mvnpm/esbuild/model/BundleResult.java
+++ b/core/src/main/java/io/mvnpm/esbuild/model/BundleResult.java
@@ -2,5 +2,5 @@
import java.nio.file.Path;
-public record BundleResult(Path dist, Path workDir, ExecuteResult result) {
+public record BundleResult(Path dist, Path workDir) {
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/DevResult.java b/core/src/main/java/io/mvnpm/esbuild/model/DevResult.java
new file mode 100644
index 00000000..e27b908a
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/model/DevResult.java
@@ -0,0 +1,14 @@
+package io.mvnpm.esbuild.model;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import io.mvnpm.esbuild.script.DevProcess;
+
+public record DevResult(DevProcess process) implements Closeable {
+
+ @Override
+ public void close() throws IOException {
+ process.close();
+ }
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java
index 54d192aa..4c723ccb 100644
--- a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java
+++ b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java
@@ -7,20 +7,21 @@
import java.util.Map;
import java.util.stream.Collectors;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
public record EsBuildConfig(
String esBuildVersion,
boolean bundle,
- String[] entryPoint,
+ String[] entryPoints,
boolean minify,
- boolean version,
-
Map loader,
boolean preserveSymlinks,
Target target,
- boolean watch,
-
String outdir,
String packages,
@@ -58,14 +59,10 @@ public EsBuildConfig(EsBuildConfigBuilder builder) {
builder.entryPoint,
builder.minify,
- builder.version,
-
builder.loader,
builder.preserveSymlinks,
builder.target,
- builder.watch,
-
builder.outdir,
builder.packages,
@@ -97,13 +94,11 @@ public EsBuildConfigBuilder edit() {
return new EsBuildConfigBuilder()
.esbuildVersion(this.esBuildVersion)
.bundle(this.bundle)
- .entryPoint(this.entryPoint)
+ .entryPoint(this.entryPoints)
.minify(this.minify)
- .version(this.version)
.loader(this.loader)
.preserveSymlinks(this.preserveSymlinks)
.target(this.target)
- .watch(this.watch)
.outDir(this.outdir)
.packages(this.packages)
.platform(this.platform)
@@ -124,7 +119,12 @@ public EsBuildConfigBuilder edit() {
public enum Format {
IIFE,
CJS,
- ESM,
+ ESM;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
}
public enum Loader {
@@ -154,7 +154,12 @@ public String toString() {
public enum Platform {
BROWSER,
NODE,
- NEUTRAL
+ NEUTRAL;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
}
public enum Target {
@@ -165,7 +170,12 @@ public enum Target {
EDGE16,
NODE10,
IE9,
- OPERA45
+ OPERA45;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
}
public String[] toParams() {
@@ -182,7 +192,7 @@ public String[] toParams() {
((List>) value).forEach(e -> result.add("--%s:%s".formatted(convertField(fieldName), e.toString())));
} else if (value instanceof Map) {
result.addAll(mapToString(fieldName, (Map, ?>) value));
- } else if ("entryPoint".equals(field.getName())) {
+ } else if ("entryPoints".equals(field.getName())) {
result.addAll(List.of((String[]) value));
} else if (!(value instanceof Boolean)) {
String fn = convertField(fieldName);
@@ -201,6 +211,53 @@ public String[] toParams() {
return result.toArray(String[]::new);
}
+ public String toJson() {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode node = mapper.createObjectNode();
+ final Field[] fields = EsBuildConfig.class.getDeclaredFields();
+ for (Field field : fields) {
+ try {
+ final Object value = field.get(this);
+ final String fieldName = field.getName();
+
+ if ("serve".equals(fieldName)) {
+ continue;
+ }
+ if (value instanceof Boolean) {
+ node.put(fieldName, (Boolean) value);
+ } else if (value instanceof Map, ?> map) {
+ if (map.isEmpty())
+ continue;
+
+ ObjectNode subNode = mapper.createObjectNode();
+ map.forEach((key, v) -> subNode.put(key.toString(), v.toString().replaceAll("_", "-")));
+ node.set(fieldName, subNode);
+ } else if (value instanceof List> list) {
+ if (list.isEmpty())
+ continue;
+ ArrayNode arrayNode = mapper.createArrayNode();
+ list.forEach(v -> arrayNode.add(v.toString()));
+ node.set(fieldName, arrayNode);
+ } else if (value instanceof String[] list) {
+ if (list.length == 0)
+ continue;
+ ArrayNode arrayNode = mapper.createArrayNode();
+ Arrays.stream(list).toList().forEach(arrayNode::add);
+ node.set(fieldName, arrayNode);
+ } else if (value != null) {
+ node.put(fieldName, value.toString());
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ try {
+ return mapper.writeValueAsString(node);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private static String convertField(String field) {
final String[] split = field.split("(?=\\p{Upper})");
return Arrays.stream(split).map(String::toLowerCase).collect(Collectors.joining("-"));
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java
index d04795d2..8055ed72 100644
--- a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java
+++ b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java
@@ -58,7 +58,7 @@ public class EsBuildConfigBuilder {
List external = new ArrayList<>();
- EsBuildConfigBuilder() {
+ public EsBuildConfigBuilder() {
}
public EsBuildConfigBuilder withDefault() {
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/WatchStartResult.java b/core/src/main/java/io/mvnpm/esbuild/model/WatchStartResult.java
deleted file mode 100644
index 4ecf5434..00000000
--- a/core/src/main/java/io/mvnpm/esbuild/model/WatchStartResult.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.mvnpm.esbuild.model;
-
-import java.io.Closeable;
-
-public record WatchStartResult(WatchBuildResult firstBuildResult, WatchProcess process) {
-
- public interface WatchProcess extends Closeable {
-
- boolean isAlive();
-
- }
-
-}
diff --git a/core/src/main/java/io/mvnpm/esbuild/script/BuildScript.java b/core/src/main/java/io/mvnpm/esbuild/script/BuildScript.java
new file mode 100644
index 00000000..52476df4
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/script/BuildScript.java
@@ -0,0 +1,120 @@
+package io.mvnpm.esbuild.script;
+
+import java.nio.file.Path;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.caoccao.javet.enums.JSRuntimeType;
+import com.caoccao.javet.enums.V8AwaitMode;
+import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interop.NodeRuntime;
+import com.caoccao.javet.interop.V8Locker;
+import com.caoccao.javet.interop.engine.IJavetEngine;
+import com.caoccao.javet.interop.engine.IJavetEnginePool;
+import com.caoccao.javet.interop.engine.JavetEngineConfig;
+import com.caoccao.javet.interop.engine.JavetEnginePool;
+import com.caoccao.javet.values.reference.V8ValueGlobalObject;
+import com.caoccao.javet.values.reference.V8ValueObject;
+import com.caoccao.javet.values.reference.V8ValuePromise;
+
+import io.mvnpm.esbuild.BundleException;
+import io.mvnpm.esbuild.install.EsBuildDeps;
+import io.mvnpm.esbuild.model.EsBuildConfig;
+
+public class BuildScript {
+
+ private static final AtomicReference> POOL_REF = new AtomicReference<>();
+ // language=JavaScript
+ private static final String SCRIPT = """
+ const esbuild = require('esbuild');
+ const requiredPlugins = [];
+ for(let plugin of plugins) {
+ console.debug(`Adding ${plugin}`);
+ requiredPlugins.push(require(plugin).default.call());
+ }
+
+ async function build () {
+ const {watch, ...options} = JSON.parse(config);
+ console.log(`Running esbuild (${esbuild.version})`);
+ try {
+ await esbuild.build({
+ ...options,
+ logLevel: "warning",
+ plugins: requiredPlugins
+ });
+ console.log("build finished");
+ return {success: true};
+ } catch(e) {
+ console.log("Error during build.");
+ return {success: false, error: e};
+ }
+ }
+ """;
+
+ public static void build(Path workDir, EsBuildConfig config) {
+ try (IJavetEngine javetEngine = getOrCreatePool().getEngine()) {
+ try (NodeRuntime nodeRuntime = javetEngine.getV8Runtime()) {
+ nodeRuntime.allowEval(true);
+ try (V8Locker ignored = nodeRuntime.getV8Locker()) {
+ try (V8ValueGlobalObject globalObject = nodeRuntime.getGlobalObject()) {
+ // bind config
+ globalObject.set("plugins", EsBuildDeps.get().plugins());
+ globalObject.set("config", config.toJson());
+ globalObject.set("workDir", workDir.toString());
+
+ if (!globalObject.has("build")) {
+ nodeRuntime.getExecutor(SCRIPT).setResourceName(workDir.resolve("build.js").toString())
+ .executeVoid();
+ }
+
+ try (V8ValuePromise promise = nodeRuntime.getGlobalObject().invoke("build")) {
+ while (!promise.isFulfilled() && !Thread.currentThread().isInterrupted()) {
+ nodeRuntime.await(V8AwaitMode.RunOnce);
+ }
+ try (final V8ValueObject result = promise.getResult()) {
+ final boolean success = result.getBoolean("success");
+ if (!success) {
+ throw new BundleException("Error while executing Esbuild", result.getString("error"));
+ }
+ }
+ } catch (JavetException e) {
+ throw new RuntimeException("Error while preparing Esbuild script", e);
+ }
+ }
+ }
+ }
+ } catch (JavetException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private static IJavetEnginePool getOrCreatePool() {
+ return POOL_REF.updateAndGet(existing -> {
+ if (existing != null) {
+ return existing;
+ }
+ return createPool();
+ });
+ }
+
+ private static JavetEnginePool createPool() {
+ JavetEngineConfig config = new JavetEngineConfig();
+ config.setJSRuntimeType(JSRuntimeType.Node);
+ config.setAllowEval(true);
+ return new JavetEnginePool<>(config);
+ }
+
+ static {
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ IJavetEnginePool pool = POOL_REF.getAndSet(null);
+ if (pool != null) {
+ try {
+ pool.close();
+ } catch (Exception e) {
+ // Log or ignore
+ }
+ }
+ }));
+ }
+
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/script/DevProcess.java b/core/src/main/java/io/mvnpm/esbuild/script/DevProcess.java
new file mode 100644
index 00000000..160f166b
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/script/DevProcess.java
@@ -0,0 +1,17 @@
+package io.mvnpm.esbuild.script;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.file.Path;
+
+public interface DevProcess extends Closeable {
+ void init();
+
+ void build() throws IOException;
+
+ Path workDir();
+
+ Path dist();
+
+ boolean isAlive();
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/script/DevScript.java b/core/src/main/java/io/mvnpm/esbuild/script/DevScript.java
new file mode 100644
index 00000000..2f36db3d
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/script/DevScript.java
@@ -0,0 +1,177 @@
+package io.mvnpm.esbuild.script;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.caoccao.javet.enums.V8AwaitMode;
+import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interop.NodeRuntime;
+import com.caoccao.javet.interop.V8Host;
+import com.caoccao.javet.values.reference.V8ValueGlobalObject;
+import com.caoccao.javet.values.reference.V8ValueObject;
+import com.caoccao.javet.values.reference.V8ValuePromise;
+
+import io.mvnpm.esbuild.BundleException;
+import io.mvnpm.esbuild.install.EsBuildDeps;
+import io.mvnpm.esbuild.model.EsBuildConfig;
+
+/**
+ * Calling build is Threadsafe as soon as init has been called before without a risk of race
+ */
+public class DevScript implements DevProcess {
+ private final Path workDir;
+ private final EsBuildConfig config;
+ private final Path outDir;
+ private final AtomicReference nodeRuntime = new AtomicReference<>();
+ private final AtomicReference globalObject = new AtomicReference<>();
+ private final Object lock = new Object();
+
+ // language=JavaScript
+ private static final String SCRIPT = """
+
+ const esbuild = require('esbuild');
+
+ const requiredPlugins = [];
+
+ for (let plugin of plugins) {
+ console.debug(`Adding ${plugin}`);
+ requiredPlugins.push(require(plugin).default.call());
+ }
+
+
+ let options = JSON.parse(config);
+
+ let context = null;
+
+
+ async function build() {
+ console.log(`Running esbuild (${esbuild.version})`);
+ try {
+ console.debug("Esbuild config:" + config);
+ if (context == null) {
+ context = await esbuild.context({
+ ...options,
+ logLevel: "warning",
+ plugins: requiredPlugins
+ });
+ }
+ let result = await context.rebuild();
+ if (result.errors.length > 0) {
+ console.debug("build finished with errors: " + result.errors);
+ return {success: false, error: result.errors[0].text};
+ }
+
+ return {success: true};
+ } catch (e) {
+ console.debug("build exception", e);
+ return {success: false, error: e.message};
+ }
+ }
+
+ async function close() {
+ console.debug('Closing Esbuild Dev.');
+ if (context) {
+ await context.dispose();
+ console.log('Esbuild Dev process closed.');
+ }
+ esbuild.stop();
+ options = null;
+ };
+
+
+ process.on('unhandledRejection', (reason, promise) => {
+ close();
+ });
+ """;
+
+ public DevScript(Path workDir, EsBuildConfig config) {
+ this.workDir = workDir;
+ this.config = config;
+ final String out = config.outdir() != null ? config.outdir() : "dist";
+ this.outDir = workDir.resolve(out);
+ }
+
+ @Override
+ public void init() {
+ if (nodeRuntime.get() != null) {
+ throw new IllegalStateException("DevScript has already been initialized");
+ }
+ try {
+ nodeRuntime.set(V8Host.getNodeInstance().createV8Runtime());
+ nodeRuntime.get().allowEval(true);
+ globalObject.set(nodeRuntime.get().getGlobalObject());
+ globalObject.get().set("plugins", EsBuildDeps.get().plugins());
+ globalObject.get().set("config", config.toJson());
+ globalObject.get().set("workDir", workDir.toString());
+ nodeRuntime.get().getExecutor(SCRIPT).setResourceName(workDir.resolve("build.js").toString()).executeVoid();
+ } catch (JavetException e) {
+ close();
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void build() throws IOException {
+ if (nodeRuntime.get() == null) {
+ throw new IllegalStateException("DevScript has not been initialized");
+ }
+ invokeBuild();
+ }
+
+ private void invokeBuild() {
+ try (V8ValuePromise promise = globalObject.get().invoke("build")) {
+ while (!promise.isFulfilled() && !Thread.currentThread().isInterrupted()) {
+ nodeRuntime.get().await(V8AwaitMode.RunOnce);
+ }
+ try (final V8ValueObject result = promise.getResult()) {
+ final boolean success = result.getBoolean("success");
+ if (!success) {
+ throw new BundleException("Error while executing Esbuild", result.getString("error"));
+ }
+ }
+
+ } catch (JavetException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ @Override
+ public Path workDir() {
+ return workDir;
+ }
+
+ @Override
+ public Path dist() {
+ return outDir;
+ }
+
+ @Override
+ public boolean isAlive() {
+ return nodeRuntime.get() != null && !nodeRuntime.get().isClosed();
+ }
+
+ @Override
+ public void close() {
+ final NodeRuntime runtime = this.nodeRuntime.getAndSet(null);
+ final V8ValueGlobalObject obj = this.globalObject.getAndSet(null);
+ if (runtime != null) {
+ try {
+ if (obj.has("close")) {
+ try (final V8ValuePromise promise = obj.invoke("close")) {
+ while (!promise.isFulfilled() && !Thread.currentThread().isInterrupted()) {
+ runtime.await(V8AwaitMode.RunOnce);
+ }
+ }
+ }
+ runtime.lowMemoryNotification();
+ runtime.close();
+ } catch (JavetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/script/ScriptRunner.java b/core/src/main/java/io/mvnpm/esbuild/script/ScriptRunner.java
new file mode 100644
index 00000000..0944202d
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/script/ScriptRunner.java
@@ -0,0 +1,36 @@
+package io.mvnpm.esbuild.script;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.logging.Logger;
+
+import io.mvnpm.esbuild.model.EsBuildConfig;
+
+public class ScriptRunner {
+
+ private static final Logger logger = Logger.getLogger(ScriptRunner.class.getName());
+
+ private final Path workDir;
+ private final EsBuildConfig esBuildConfig;
+
+ public ScriptRunner(Path workDir, EsBuildConfig esBuildConfig) {
+ this.workDir = workDir;
+ this.esBuildConfig = esBuildConfig;
+ }
+
+ public static Path getOutDir(Path workDir, EsBuildConfig config) {
+ final String out = config.outdir() != null ? config.outdir() : "dist";
+ return workDir.resolve(out);
+ }
+
+ public void build() throws IOException {
+ //WebDepsInstaller.install(workDir.resolve("node_modules"), getDependencies());
+ BuildScript.build(workDir, esBuildConfig);
+ }
+
+ public DevProcess dev() throws IOException {
+ //WebDepsInstaller.install(workDir.resolve("node_modules"), getDependencies());
+ return new DevScript(workDir, esBuildConfig);
+ }
+
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/util/Archives.java b/core/src/main/java/io/mvnpm/esbuild/util/Archives.java
index 28919be7..3372fa31 100644
--- a/core/src/main/java/io/mvnpm/esbuild/util/Archives.java
+++ b/core/src/main/java/io/mvnpm/esbuild/util/Archives.java
@@ -6,6 +6,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -52,6 +54,11 @@ private static void extractEntry(Path target, String name, boolean isDirectory,
}
Files.copy(is, newPath, StandardCopyOption.REPLACE_EXISTING);
+ if (newPath.toString().contains("/bin/")) {
+ Set permissions = Files.getPosixFilePermissions(newPath);
+ permissions.add(PosixFilePermission.OWNER_EXECUTE);
+ Files.setPosixFilePermissions(newPath, permissions);
+ }
}
}
diff --git a/core/src/main/resources-filtered/esbuild-java-version.properties b/core/src/main/resources-filtered/esbuild-java-version.properties
index 1254bac2..05b6a006 100644
--- a/core/src/main/resources-filtered/esbuild-java-version.properties
+++ b/core/src/main/resources-filtered/esbuild-java-version.properties
@@ -1 +1 @@
-esbuild.version=${esbuild.version}
\ No newline at end of file
+esbuild.version=${esbuild.version}
diff --git a/core/src/test/java/io/mvnpm/esbuild/BundlerTest.java b/core/src/test/java/io/mvnpm/esbuild/BundlerTest.java
deleted file mode 100644
index a18b3ab0..00000000
--- a/core/src/test/java/io/mvnpm/esbuild/BundlerTest.java
+++ /dev/null
@@ -1,274 +0,0 @@
-package io.mvnpm.esbuild;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.junit.jupiter.api.Test;
-
-import io.mvnpm.esbuild.model.*;
-import io.mvnpm.esbuild.model.WebDependency.WebDependencyType;
-
-public class BundlerTest {
-
- @Test
- public void shouldBundleMvnpm() throws URISyntaxException, IOException {
- executeTest(List.of("/mvnpm/stimulus-3.2.1.jar"), WebDependencyType.MVNPM, "application-mvnpm.js", true);
- }
-
- @Test
- public void shouldBundleMvnpmSources() throws URISyntaxException, IOException {
- executeTest(List.of("/mvnpm/moment-2.29.4-sources.jar"), WebDependencyType.MVNPM,
- "application-mvnpm.ts", true);
- }
-
- @Test
- void shouldBundleWithScss() throws IOException, URISyntaxException {
- final Path root = new File(getClass().getResource("/scss/").toURI()).toPath();
-
- final BundleOptions options = BundleOptions.builder()
- .withWorkDir(root)
- .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
- .withDependencies(getJars(List.of("/mvnpm/stimulus-3.2.1.jar", "/mvnpm/bootstrap-5.2.3.jar")),
- WebDependencyType.MVNPM)
- .addEntryPoint("app.js").build();
-
- Bundler.bundle(options, true);
-
- assertTrue(options.workDir().resolve("dist").resolve("app.js").toFile().exists());
- assertTrue(options.workDir().resolve("dist").resolve("app.css").toFile().exists());
- }
-
- @Test
- void shouldBundleWithScssImports() throws IOException, URISyntaxException {
- final Path root = new File(getClass().getResource("/scss/").toURI()).toPath();
-
- final BundleOptions options = BundleOptions.builder()
- .withWorkDir(root)
- .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
- .addEntryPoint("import.scss").build();
-
- Bundler.bundle(options, true);
-
- assertTrue(options.workDir().resolve("dist").resolve("import.css").toFile().exists());
- }
-
- @Test
- void shouldBundleWithScssImportsFilesBeforeFolders() throws IOException, URISyntaxException {
- final Path root = new File(getClass().getResource("/scss/partials").toURI()).toPath();
-
- final BundleOptions options = BundleOptions.builder()
- .withWorkDir(root)
- .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
- .addEntryPoint("test.scss").build();
-
- Bundler.bundle(options, true);
-
- assertTrue(options.workDir().resolve("dist").resolve("test.css").toFile().exists());
- }
-
- @Test
- public void shouldBundleMvnpmAndCreatePackageJson() throws URISyntaxException, IOException {
- executeTest(List.of("/mvnpm/stimulus-3.2.0.jar"), WebDependencyType.MVNPM, "application-mvnpm.js", true);
- }
-
- @Test
- public void shouldBundleMvnpmWithoutPackageJson() throws URISyntaxException, IOException {
- executeTest(List.of("/mvnpm/polymer-3.5.1.jar"), WebDependencyType.MVNPM, "application-mvnpm-importmap.js", true);
- }
-
- @Test
- public void shouldBundle() throws URISyntaxException, IOException {
- executeTest(List.of("/webjars/htmx.org-1.8.4.jar"), WebDependencyType.WEBJARS, "application-webjar.js", true);
- }
-
- @Test
- public void shouldWatchExitWithError() throws URISyntaxException, IOException, InterruptedException {
- final BundleOptions options = getBundleOptions(
- List.of("/mvnpm/stimulus-3.2.1.jar"),
- WebDependencyType.MVNPM,
- "application-mvnpm.js").withEsConfig(
- EsBuildConfig.builder()
- .fixedEntryNames()
- .define("foo", "\"bar") // <- looks like you might be missing a closing quote here?
- .build())
- .build();
-
- ExecutorService executor = Executors.newFixedThreadPool(10);
- AtomicReference r = new AtomicReference<>();
- try {
- for (int i = 0; i < 100; i++) {
- final int idx = i;
- executor.submit(() -> {
- System.out.println("Running task " + idx);
- final Watch watch;
- try {
- watch = Bundler.watch(options, (wr) -> {
- }, true);
- r.set(watch);
- } catch (IOException e) {
- // good
- }
-
- });
- }
- } finally {
- executor.shutdown();
- }
- executor.awaitTermination(3, TimeUnit.SECONDS);
- if (r.get() != null) {
- throw new RuntimeException(r.get().toString());
- }
- }
-
- @Test
- public void shouldWatch() throws URISyntaxException, IOException, InterruptedException {
- // given
- final BundleOptions options = getBundleOptions(List.of("/mvnpm/stimulus-3.2.1.jar"),
- WebDependencyType.MVNPM,
- "application-mvnpm.js").withEsConfig(EsBuildConfig.builder().fixedEntryNames().build()).build();
-
- // when
- AtomicReference latch = new AtomicReference<>(new CountDownLatch(1));
- AtomicReference bundleException = new AtomicReference<>();
- final Watch watch = Bundler.watch(options, (r) -> {
- if (!r.isSuccess()) {
- bundleException.set(r.bundleException());
- }
- latch.get().countDown();
- }, true);
-
- // then
- assertTrue(latch.get().getCount() == 1, "First build is not using the listener");
- assertTrue(watch.firstBuildResult().isSuccess(), "first build is success");
- assertTrue(watch.isAlive(), "process is alive");
- final Path app = watch.workDir().resolve("application-mvnpm.js");
- assertTrue(Files.exists(app));
- final Path distApp = watch.dist().resolve("application-mvnpm.js");
- assertTrue(Files.exists(distApp));
-
- // when
- Files.writeString(app, "\nalert(\"foo\");", StandardOpenOption.APPEND);
- assertTrue(latch.get().await(2, TimeUnit.SECONDS));
- assertNull(bundleException.get(), "No error during bundling");
- assertTrue(Files.readString(distApp).contains("alert(\"foo\");"));
-
- // then
- watch.close();
-
- assertFalse(watch.isAlive());
- }
-
- @Test
- public void shouldWatchWithError() throws URISyntaxException, IOException, InterruptedException {
-
- // given
- final BundleOptions options = getBundleOptions(List.of("/mvnpm/stimulus-3.2.1.jar"),
- WebDependencyType.MVNPM,
- "application-error.js").withEsConfig(EsBuildConfig.builder().fixedEntryNames().build()).build();
-
- // when
- AtomicReference latch = new AtomicReference<>(new CountDownLatch(1));
- AtomicReference bundleException = new AtomicReference<>();
- final Watch watch = Bundler.watch(options, (r) -> {
- if (!r.isSuccess()) {
- bundleException.set(r.bundleException());
- }
- latch.get().countDown();
- }, true);
-
- // then
- assertTrue(latch.get().getCount() == 1, "First build is not using the listener");
- assertTrue(watch.isAlive(), "process is alive");
- assertNotNull(watch.firstBuildResult().bundleException(), "Error during bundling");
- assertTrue(watch.firstBuildResult().bundleException().output().contains("[ERROR] Could not resolve \"\""));
-
- final Path app = watch.workDir().resolve("application-error.js");
- assertTrue(Files.exists(app));
-
- // when
- Files.writeString(app, "alert(\"foo\");", StandardOpenOption.TRUNCATE_EXISTING);
-
- // then
- assertTrue(latch.get().await(2, TimeUnit.SECONDS));
- assertNull(bundleException.get(), "No error during bundling");
- final Path distApp = watch.dist().resolve("application-error.js");
- assertTrue(Files.exists(distApp));
- assertTrue(Files.readString(distApp).contains("alert(\"foo\");"));
-
- // then
- watch.close();
- }
-
- @Test
- public void shouldThrowException() {
- assertThrows(BundleException.class, () -> {
- executeTest(List.of("/mvnpm/stimulus-3.2.1.jar"), WebDependencyType.MVNPM, "application-error.js", false);
- });
- }
-
- @Test
- public void shouldResolveRelativeFolders() throws URISyntaxException, IOException {
- // given
- final Path root = new File(getClass().getResource("/path/").toURI()).toPath();
- final BundleOptions bundleOptions = BundleOptions.builder().withWorkDir(root)
- .addAutoEntryPoint(root, "main", List.of("foo/bar.js")).build();
-
- // when
- final BundleResult result = Bundler.bundle(bundleOptions, true);
-
- // then
- assertTrue(result.dist().toFile().exists());
- }
-
- private void executeTest(List jarNames, WebDependencyType type, String scriptName, boolean check)
- throws URISyntaxException, IOException {
- final BundleOptions bundleOptions = getBundleOptions(jarNames, type, scriptName).build();
- final BundleResult result = Bundler.bundle(bundleOptions, true);
-
- if (check) {
- assertTrue(result.dist().toFile().exists());
- }
-
- }
-
- private BundleOptionsBuilder getBundleOptions(List jarNames, WebDependencyType type, String scriptName)
- throws URISyntaxException {
- final List jars = getJars(jarNames);
- final Path rootDir = new File(getClass().getResource("/").toURI()).toPath();
- final BundleOptionsBuilder bundleOptionsBuilder = BundleOptions.builder().withDependencies(jars, type);
- if (scriptName != null) {
- bundleOptionsBuilder
- .addEntryPoint(rootDir, scriptName);
- }
- return bundleOptionsBuilder;
- }
-
- private List getJars(List jarNames) {
- final List jars = jarNames.stream().map(jarName -> {
- try {
- final URL resource = getClass().getResource(jarName);
- if (resource == null) {
- throw new RuntimeException("Could not find resource: " + jarName);
- }
- return new File(resource.toURI()).toPath();
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }).toList();
- return jars;
- }
-
-}
diff --git a/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java b/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java
deleted file mode 100644
index 511b3c96..00000000
--- a/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.mvnpm.esbuild;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.junit.jupiter.api.Test;
-
-import io.mvnpm.esbuild.model.EsBuildConfig;
-import io.mvnpm.esbuild.model.EsBuildConfigBuilder;
-import io.mvnpm.esbuild.model.ExecuteResult;
-import io.mvnpm.esbuild.resolve.Resolver;
-
-public class ExecuteTest {
-
- @Test
- public void shouldExecuteEsBuild() throws IOException {
- final EsBuildConfigBuilder esBuildConfig = EsBuildConfig.builder();
- esBuildConfig.version(true);
- final String defaultVersion = Bundler.ESBUILD_EMBEDDED_VERSION;
- final Path path = Resolver.create().resolve(defaultVersion);
- String workingDirectory = System.getProperty("user.dir");
- final ExecuteResult executeResult = new Execute(Paths.get(workingDirectory), path.toFile(), esBuildConfig.build())
- .executeAndWait();
- assertEquals(defaultVersion + "\n", executeResult.output());
- }
-}
diff --git a/core/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java b/core/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
deleted file mode 100644
index 9926effa..00000000
--- a/core/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.mvnpm.esbuild.resolve;
-
-import java.io.IOException;
-
-import io.mvnpm.esbuild.Bundler;
-import io.mvnpm.esbuild.util.PathUtils;
-
-public abstract class BundleTester {
-
- public static void cleanUp(String version) throws IOException {
- PathUtils.deleteRecursive(Resolvers.getLocation(version));
- }
-
- public static void cleanUpDefault() throws IOException {
- cleanUp(Bundler.ESBUILD_EMBEDDED_VERSION);
- }
-}
diff --git a/core/src/test/resources/application-mvnpm.js b/core/src/test/resources/application-mvnpm.js
deleted file mode 100644
index 1b5d3ef2..00000000
--- a/core/src/test/resources/application-mvnpm.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { Application } from "@hotwired/stimulus";
-
-Application.start();
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..586738ed
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1515 @@
+{
+ "name": "esbuild-java",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "esbuild-java",
+ "version": "1.0.0",
+ "dependencies": {
+ "esbuild-sass-plugin": "^3.3.1"
+ }
+ },
+ "node_modules/@bufbuild/protobuf": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.9.0.tgz",
+ "integrity": "sha512-rnJenoStJ8nvmt9Gzye8nkYd6V22xUAnu4086ER7h1zJ508vStko4pMvDeQ446ilDTFpV5wnoc5YS7XvMwwMqA==",
+ "license": "(Apache-2.0 AND BSD-3-Clause)",
+ "peer": true
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
+ "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
+ "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
+ "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
+ "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
+ "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
+ "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
+ "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
+ "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
+ "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
+ "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
+ "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
+ "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
+ "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
+ "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
+ "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
+ "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
+ "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
+ "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
+ "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
+ "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
+ "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
+ "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "node-addon-api": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.1",
+ "@parcel/watcher-darwin-arm64": "2.5.1",
+ "@parcel/watcher-darwin-x64": "2.5.1",
+ "@parcel/watcher-freebsd-x64": "2.5.1",
+ "@parcel/watcher-linux-arm-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm-musl": "2.5.1",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm64-musl": "2.5.1",
+ "@parcel/watcher-linux-x64-glibc": "2.5.1",
+ "@parcel/watcher-linux-x64-musl": "2.5.1",
+ "@parcel/watcher-win32-arm64": "2.5.1",
+ "@parcel/watcher-win32-ia32": "2.5.1",
+ "@parcel/watcher-win32-x64": "2.5.1"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+ "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+ "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+ "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+ "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+ "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+ "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+ "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+ "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+ "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+ "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+ "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+ "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+ "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-builder": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz",
+ "integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
+ "license": "MIT/X11",
+ "peer": true
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/colorjs.io": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
+ "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
+ "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.10",
+ "@esbuild/android-arm": "0.25.10",
+ "@esbuild/android-arm64": "0.25.10",
+ "@esbuild/android-x64": "0.25.10",
+ "@esbuild/darwin-arm64": "0.25.10",
+ "@esbuild/darwin-x64": "0.25.10",
+ "@esbuild/freebsd-arm64": "0.25.10",
+ "@esbuild/freebsd-x64": "0.25.10",
+ "@esbuild/linux-arm": "0.25.10",
+ "@esbuild/linux-arm64": "0.25.10",
+ "@esbuild/linux-ia32": "0.25.10",
+ "@esbuild/linux-loong64": "0.25.10",
+ "@esbuild/linux-mips64el": "0.25.10",
+ "@esbuild/linux-ppc64": "0.25.10",
+ "@esbuild/linux-riscv64": "0.25.10",
+ "@esbuild/linux-s390x": "0.25.10",
+ "@esbuild/linux-x64": "0.25.10",
+ "@esbuild/netbsd-arm64": "0.25.10",
+ "@esbuild/netbsd-x64": "0.25.10",
+ "@esbuild/openbsd-arm64": "0.25.10",
+ "@esbuild/openbsd-x64": "0.25.10",
+ "@esbuild/openharmony-arm64": "0.25.10",
+ "@esbuild/sunos-x64": "0.25.10",
+ "@esbuild/win32-arm64": "0.25.10",
+ "@esbuild/win32-ia32": "0.25.10",
+ "@esbuild/win32-x64": "0.25.10"
+ }
+ },
+ "node_modules/esbuild-sass-plugin": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-3.3.1.tgz",
+ "integrity": "sha512-SnO1ls+d52n6j8gRRpjexXI8MsHEaumS0IdDHaYM29Y6gakzZYMls6i9ql9+AWMSQk/eryndmUpXEgT34QrX1A==",
+ "license": "MIT",
+ "dependencies": {
+ "resolve": "^1.22.8",
+ "safe-identifier": "^0.4.2",
+ "sass": "^1.71.1"
+ },
+ "peerDependencies": {
+ "esbuild": ">=0.20.1",
+ "sass-embedded": "^1.71.1"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/immutable": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
+ "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
+ "license": "MIT"
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "license": "MIT"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/safe-identifier": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz",
+ "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==",
+ "license": "ISC"
+ },
+ "node_modules/sass": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz",
+ "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^4.0.0",
+ "immutable": "^5.0.2",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
+ "node_modules/sass-embedded": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.93.2.tgz",
+ "integrity": "sha512-FvQdkn2dZ8DGiLgi0Uf4zsj7r/BsiLImNa5QJ10eZalY6NfZyjrmWGFcuCN5jNwlDlXFJnftauv+UtvBKLvepQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@bufbuild/protobuf": "^2.5.0",
+ "buffer-builder": "^0.2.0",
+ "colorjs.io": "^0.5.0",
+ "immutable": "^5.0.2",
+ "rxjs": "^7.4.0",
+ "supports-color": "^8.1.1",
+ "sync-child-process": "^1.0.2",
+ "varint": "^6.0.0"
+ },
+ "bin": {
+ "sass": "dist/bin/sass.js"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "optionalDependencies": {
+ "sass-embedded-all-unknown": "1.93.2",
+ "sass-embedded-android-arm": "1.93.2",
+ "sass-embedded-android-arm64": "1.93.2",
+ "sass-embedded-android-riscv64": "1.93.2",
+ "sass-embedded-android-x64": "1.93.2",
+ "sass-embedded-darwin-arm64": "1.93.2",
+ "sass-embedded-darwin-x64": "1.93.2",
+ "sass-embedded-linux-arm": "1.93.2",
+ "sass-embedded-linux-arm64": "1.93.2",
+ "sass-embedded-linux-musl-arm": "1.93.2",
+ "sass-embedded-linux-musl-arm64": "1.93.2",
+ "sass-embedded-linux-musl-riscv64": "1.93.2",
+ "sass-embedded-linux-musl-x64": "1.93.2",
+ "sass-embedded-linux-riscv64": "1.93.2",
+ "sass-embedded-linux-x64": "1.93.2",
+ "sass-embedded-unknown-all": "1.93.2",
+ "sass-embedded-win32-arm64": "1.93.2",
+ "sass-embedded-win32-x64": "1.93.2"
+ }
+ },
+ "node_modules/sass-embedded-all-unknown": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.93.2.tgz",
+ "integrity": "sha512-GdEuPXIzmhRS5J7UKAwEvtk8YyHQuFZRcpnEnkA3rwRUI27kwjyXkNeIj38XjUQ3DzrfMe8HcKFaqWGHvblS7Q==",
+ "cpu": [
+ "!arm",
+ "!arm64",
+ "!riscv64",
+ "!x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "sass": "1.93.2"
+ }
+ },
+ "node_modules/sass-embedded-android-arm": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.93.2.tgz",
+ "integrity": "sha512-I8bpO8meZNo5FvFx5FIiE7DGPVOYft0WjuwcCCdeJ6duwfkl6tZdatex1GrSigvTsuz9L0m4ngDcX/Tj/8yMow==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-android-arm64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.93.2.tgz",
+ "integrity": "sha512-346f4iVGAPGcNP6V6IOOFkN5qnArAoXNTPr5eA/rmNpeGwomdb7kJyQ717r9rbJXxOG8OAAUado6J0qLsjnjXQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-android-riscv64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.93.2.tgz",
+ "integrity": "sha512-hSMW1s4yJf5guT9mrdkumluqrwh7BjbZ4MbBW9tmi1DRDdlw1Wh9Oy1HnnmOG8x9XcI1qkojtPL6LUuEJmsiDg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-android-x64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.93.2.tgz",
+ "integrity": "sha512-JqktiHZduvn+ldGBosE40ALgQ//tGCVNAObgcQ6UIZznEJbsHegqStqhRo8UW3x2cgOO2XYJcrInH6cc7wdKbw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-darwin-arm64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.93.2.tgz",
+ "integrity": "sha512-qI1X16qKNeBJp+M/5BNW7v/JHCDYWr1/mdoJ7+UMHmP0b5AVudIZtimtK0hnjrLnBECURifd6IkulybR+h+4UA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-darwin-x64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.93.2.tgz",
+ "integrity": "sha512-4KeAvlkQ0m0enKUnDGQJZwpovYw99iiMb8CTZRSsQm8Eh7halbJZVmx67f4heFY/zISgVOCcxNg19GrM5NTwtA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-arm": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.93.2.tgz",
+ "integrity": "sha512-N3+D/ToHtzwLDO+lSH05Wo6/KRxFBPnbjVHASOlHzqJnK+g5cqex7IFAp6ozzlRStySk61Rp6d+YGrqZ6/P0PA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-arm64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.93.2.tgz",
+ "integrity": "sha512-9ftX6nd5CsShJqJ2WRg+ptaYvUW+spqZfJ88FbcKQBNFQm6L87luj3UI1rB6cP5EWrLwHA754OKxRJyzWiaN6g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-musl-arm": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.93.2.tgz",
+ "integrity": "sha512-XBTvx66yRenvEsp3VaJCb3HQSyqCsUh7R+pbxcN5TuzueybZi0LXvn9zneksdXcmjACMlMpIVXi6LyHPQkYc8A==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-musl-arm64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.93.2.tgz",
+ "integrity": "sha512-+3EHuDPkMiAX5kytsjEC1bKZCawB9J6pm2eBIzzLMPWbf5xdx++vO1DpT7hD4bm4ZGn0eVHgSOKIfP6CVz6tVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-musl-riscv64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.93.2.tgz",
+ "integrity": "sha512-0sB5kmVZDKTYzmCSlTUnjh6mzOhzmQiW/NNI5g8JS4JiHw2sDNTvt1dsFTuqFkUHyEOY3ESTsfHHBQV8Ip4bEA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-musl-x64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.93.2.tgz",
+ "integrity": "sha512-t3ejQ+1LEVuHy7JHBI2tWHhoMfhedUNDjGJR2FKaLgrtJntGnyD1RyX0xb3nuqL/UXiEAtmTmZY+Uh3SLUe1Hg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-riscv64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.93.2.tgz",
+ "integrity": "sha512-e7AndEwAbFtXaLy6on4BfNGTr3wtGZQmypUgYpSNVcYDO+CWxatKVY4cxbehMPhxG9g5ru+eaMfynvhZt7fLaA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-linux-x64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.93.2.tgz",
+ "integrity": "sha512-U3EIUZQL11DU0xDDHXexd4PYPHQaSQa2hzc4EzmhHqrAj+TyfYO94htjWOd+DdTPtSwmLp+9cTWwPZBODzC96w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-unknown-all": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.93.2.tgz",
+ "integrity": "sha512-7VnaOmyewcXohiuoFagJ3SK5ddP9yXpU0rzz+pZQmS1/+5O6vzyFCUoEt3HDRaLctH4GT3nUGoK1jg0ae62IfQ==",
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "!android",
+ "!darwin",
+ "!linux",
+ "!win32"
+ ],
+ "peer": true,
+ "dependencies": {
+ "sass": "1.93.2"
+ }
+ },
+ "node_modules/sass-embedded-win32-arm64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.93.2.tgz",
+ "integrity": "sha512-Y90DZDbQvtv4Bt0GTXKlcT9pn4pz8AObEjFF8eyul+/boXwyptPZ/A1EyziAeNaIEIfxyy87z78PUgCeGHsx3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/sass-embedded-win32-x64": {
+ "version": "1.93.2",
+ "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.93.2.tgz",
+ "integrity": "sha512-BbSucRP6PVRZGIwlEBkp+6VQl2GWdkWFMN+9EuOTPrLxCJZoq+yhzmbjspd3PeM8+7WJ7AdFu/uRYdO8tor1iQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sync-child-process": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
+ "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "sync-message-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/sync-message-port": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz",
+ "integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD",
+ "peer": true
+ },
+ "node_modules/varint": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
+ "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
+ "license": "MIT",
+ "peer": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..7ffe6a77
--- /dev/null
+++ b/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "esbuild-java",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/mvnpm/esbuild-java"
+ },
+ "private": true,
+ "dependencies": {
+ "esbuild-sass-plugin": "^3.3.1"
+ }
+}
diff --git a/plugin-sass/pom.xml b/plugin-sass/pom.xml
new file mode 100644
index 00000000..345b9d1f
--- /dev/null
+++ b/plugin-sass/pom.xml
@@ -0,0 +1,216 @@
+
+
+ 4.0.0
+
+ io.mvnpm
+ esbuild-java-parent
+ 999-SNAPSHOT
+
+ esbuild-java-plugin-sass
+ Esbuild Java - Plugin Sass
+ Sass plugin for Esbuild Java
+
+ 3.3.1
+ 1.89.1
+
+
+
+ io.mvnpm
+ esbuild-java
+ ${project.version}
+
+
+
+ org.mvnpm
+ esbuild-sass-plugin
+ ${esbuild-sass-plugin.version}
+
+
+ org.mvnpm
+ sass
+ ${sass.version}
+
+
+ io.mvnpm
+ esbuild-java-testing
+ ${project.version}
+ test
+
+
+
+
+ locker
+
+
+ !unlocked
+
+
+
+
+
+ org.mvnpm.at.bufbuild
+ protobuf
+ 2.9.0
+
+
+ org.mvnpm.at.esbuild
+ darwin-arm64
+ 0.25.10
+
+
+ org.mvnpm.at.esbuild
+ linux-arm
+ 0.25.10
+
+
+ org.mvnpm
+ buffer-builder
+ 0.2.0
+
+
+ org.mvnpm
+ chokidar
+ 4.0.3
+
+
+ org.mvnpm
+ colorjs.io
+ 0.5.2
+
+
+ org.mvnpm
+ esbuild-sass-plugin
+ 3.3.1
+
+
+ org.mvnpm
+ esbuild
+ 0.25.10
+
+
+ org.mvnpm
+ function-bind
+ 1.1.2
+
+
+ org.mvnpm
+ has-flag
+ 4.0.0
+
+
+ org.mvnpm
+ hasown
+ 2.0.2
+
+
+ org.mvnpm
+ immutable
+ 5.1.2
+
+
+ org.mvnpm
+ is-core-module
+ 2.16.1
+
+
+ org.mvnpm
+ path-parse
+ 1.0.7
+
+
+ org.mvnpm
+ readdirp
+ 4.1.2
+
+
+ org.mvnpm
+ resolve
+ 1.22.10
+
+
+ org.mvnpm
+ rxjs
+ 7.8.2
+
+
+ org.mvnpm
+ safe-identifier
+ 0.4.2
+
+
+ org.mvnpm
+ sass-embedded
+ 1.93.2
+
+
+ org.mvnpm
+ sass
+ 1.89.1
+
+
+ org.mvnpm
+ source-map-js
+ 1.2.1
+
+
+ org.mvnpm
+ supports-color
+ 8.1.1
+
+
+ org.mvnpm
+ supports-preserve-symlinks-flag
+ 1.0.0
+
+
+ org.mvnpm
+ sync-child-process
+ 1.0.2
+
+
+ org.mvnpm
+ sync-message-port
+ 1.1.3
+
+
+ org.mvnpm
+ tslib
+ 2.8.1
+
+
+ org.mvnpm
+ varint
+ 6.0.0
+
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+
+
+ java.util.logging.config.file
+ src/test/resources/logging.properties
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ net.revelc.code.formatter
+ formatter-maven-plugin
+
+
+ net.revelc.code
+ impsort-maven-plugin
+
+
+
+
diff --git a/plugin-sass/src/test/java/io/mvnpm/esbuild/BundlerScssTest.java b/plugin-sass/src/test/java/io/mvnpm/esbuild/BundlerScssTest.java
new file mode 100644
index 00000000..7bab0764
--- /dev/null
+++ b/plugin-sass/src/test/java/io/mvnpm/esbuild/BundlerScssTest.java
@@ -0,0 +1,94 @@
+package io.mvnpm.esbuild;
+
+import static io.mvnpm.esbuild.BundlerTestHelper.getJars;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.Test;
+
+import io.mvnpm.esbuild.model.BundleOptions;
+import io.mvnpm.esbuild.model.DevResult;
+import io.mvnpm.esbuild.model.EsBuildConfig;
+import io.mvnpm.esbuild.model.WebDependency.WebDependencyType;
+
+public class BundlerScssTest {
+
+ @Test
+ void shouldBundleWithScss() throws IOException, URISyntaxException {
+
+ final Path root = prepareTest();
+
+ final BundleOptions options = BundleOptions.builder()
+ .withWorkDir(root)
+ .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
+ .withDependencies(getJars(List.of("/mvnpm/stimulus-3.2.1.jar", "/mvnpm/bootstrap-5.2.3.jar")),
+ WebDependencyType.MVNPM)
+ .addEntryPoint("app.js").build();
+
+ Bundler.bundle(options, true);
+
+ assertTrue(options.workDir().resolve("dist").resolve("app.js").toFile().exists());
+ assertTrue(options.workDir().resolve("dist").resolve("app.css").toFile().exists());
+ }
+
+ @Test
+ void shouldBundleInDevWithScss() throws IOException, URISyntaxException {
+ final Path root = prepareTest();
+
+ final BundleOptions options = BundleOptions.builder()
+ .withWorkDir(root)
+ .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
+ .withDependencies(getJars(List.of("/mvnpm/stimulus-3.2.1.jar", "/mvnpm/bootstrap-5.2.3.jar")),
+ WebDependencyType.MVNPM)
+ .addEntryPoint("app.js").build();
+
+ try (DevResult dev = Bundler.dev(options, true)) {
+ dev.process().build();
+ }
+ assertTrue(options.workDir().resolve("dist").resolve("app.js").toFile().exists());
+ assertTrue(options.workDir().resolve("dist").resolve("app.css").toFile().exists());
+ }
+
+ @Test
+ void shouldBundleWithScssImports() throws IOException, URISyntaxException {
+ final Path root = prepareTest();
+
+ final BundleOptions options = BundleOptions.builder()
+ .withWorkDir(root)
+ .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
+ .addEntryPoint("import.scss").build();
+
+ Bundler.bundle(options, true);
+
+ assertTrue(options.workDir().resolve("dist").resolve("import.css").toFile().exists());
+ }
+
+ @Test
+ void shouldBundleWithScssImportsFilesBeforeFolders() throws IOException, URISyntaxException {
+ final Path root = prepareTest();
+
+ final BundleOptions options = BundleOptions.builder()
+ .withWorkDir(root)
+ .withEsConfig(EsBuildConfig.builder().entryNames("[name]").build())
+ .addEntryPoint("partials/test.scss").build();
+
+ Bundler.bundle(options, true);
+
+ assertTrue(options.workDir().resolve("dist").resolve("test.css").toFile().exists());
+ }
+
+ static Path prepareTest() throws IOException, URISyntaxException {
+ final Path temp = Files.createTempDirectory("test-scss");
+ final Path root = new File(BundlerScssTest.class.getResource("/scss/").toURI()).toPath();
+ FileUtils.copyDirectory(root.toFile(), temp.toFile());
+ return temp;
+ }
+
+}
diff --git a/core/src/test/resources/scss/_style2.scss b/plugin-sass/src/test/resources/scss/_style2.scss
similarity index 100%
rename from core/src/test/resources/scss/_style2.scss
rename to plugin-sass/src/test/resources/scss/_style2.scss
diff --git a/core/src/test/resources/scss/app.js b/plugin-sass/src/test/resources/scss/app.js
similarity index 100%
rename from core/src/test/resources/scss/app.js
rename to plugin-sass/src/test/resources/scss/app.js
diff --git a/core/src/test/resources/scss/import.scss b/plugin-sass/src/test/resources/scss/import.scss
similarity index 100%
rename from core/src/test/resources/scss/import.scss
rename to plugin-sass/src/test/resources/scss/import.scss
diff --git a/core/src/test/resources/scss/partials/_meta.scss b/plugin-sass/src/test/resources/scss/partials/_meta.scss
similarity index 100%
rename from core/src/test/resources/scss/partials/_meta.scss
rename to plugin-sass/src/test/resources/scss/partials/_meta.scss
diff --git a/core/src/test/resources/scss/partials/_relative.scss b/plugin-sass/src/test/resources/scss/partials/_relative.scss
similarity index 100%
rename from core/src/test/resources/scss/partials/_relative.scss
rename to plugin-sass/src/test/resources/scss/partials/_relative.scss
diff --git a/core/src/test/resources/scss/partials/meta/what.scss b/plugin-sass/src/test/resources/scss/partials/meta/what.scss
similarity index 100%
rename from core/src/test/resources/scss/partials/meta/what.scss
rename to plugin-sass/src/test/resources/scss/partials/meta/what.scss
diff --git a/core/src/test/resources/scss/partials/test.scss b/plugin-sass/src/test/resources/scss/partials/test.scss
similarity index 100%
rename from core/src/test/resources/scss/partials/test.scss
rename to plugin-sass/src/test/resources/scss/partials/test.scss
diff --git a/core/src/test/resources/scss/style.scss b/plugin-sass/src/test/resources/scss/style.scss
similarity index 100%
rename from core/src/test/resources/scss/style.scss
rename to plugin-sass/src/test/resources/scss/style.scss
diff --git a/core/src/test/resources/scss/test/index.scss b/plugin-sass/src/test/resources/scss/test/index.scss
similarity index 100%
rename from core/src/test/resources/scss/test/index.scss
rename to plugin-sass/src/test/resources/scss/test/index.scss
diff --git a/pom.xml b/pom.xml
index 26ccc896..594d5133 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,15 +4,15 @@
io.mvnpm
esbuild-java-parent
- Esbuild wrapper for Java - parent
+ Esbuild Java - parent
999-SNAPSHOT
Small wrapper around esbuild to be able to use it in Java
pom
+ testing
core
- bundle-scss
- bundle-original
+ plugin-sass
https://github.com/mvnpm/esbuild-java/
diff --git a/testing/pom.xml b/testing/pom.xml
new file mode 100644
index 00000000..d8190c2c
--- /dev/null
+++ b/testing/pom.xml
@@ -0,0 +1,31 @@
+
+ 4.0.0
+
+ io.mvnpm
+ esbuild-java-parent
+ 999-SNAPSHOT
+
+ esbuild-java-testing
+ Esbuild Java - testing
+
+
+
+
+
+ io.mvnpm
+ esbuild-java
+ ${project.version}
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+
+
+
diff --git a/testing/src/main/java/io/mvnpm/esbuild/BundlerTestHelper.java b/testing/src/main/java/io/mvnpm/esbuild/BundlerTestHelper.java
new file mode 100644
index 00000000..46367578
--- /dev/null
+++ b/testing/src/main/java/io/mvnpm/esbuild/BundlerTestHelper.java
@@ -0,0 +1,70 @@
+package io.mvnpm.esbuild;
+
+import io.mvnpm.esbuild.model.BundleOptions;
+import io.mvnpm.esbuild.model.BundleOptionsBuilder;
+import io.mvnpm.esbuild.model.BundleResult;
+import io.mvnpm.esbuild.model.WebDependency.WebDependencyType;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class BundlerTestHelper {
+
+ public static void executeTest(List jarNames, WebDependencyType type, String scriptName, boolean check)
+ throws URISyntaxException, IOException {
+ final BundleOptions bundleOptions = getBundleOptions(jarNames, type, scriptName).build();
+ final BundleResult result = Bundler.bundle(bundleOptions, true);
+
+ if (check) {
+ assertTrue(result.dist().toFile().exists());
+ }
+
+ }
+
+
+ public static BundleOptionsBuilder getBundleOptions(List jarNames, WebDependencyType type, String scriptName)
+ throws URISyntaxException, IOException {
+ final List jars = getJars(jarNames);
+ final Path tempDir = Files.createTempDirectory("esbuild-test");
+ final BundleOptionsBuilder bundleOptionsBuilder = BundleOptions.builder().withDependencies(jars, type);
+ if (scriptName != null) {
+ Files.copy(new File(BundlerTestHelper.class.getResource("/" + scriptName).toURI()).toPath(), tempDir.resolve(scriptName));
+ bundleOptionsBuilder
+ .addEntryPoint(tempDir, scriptName);
+ }
+ return bundleOptionsBuilder;
+ }
+
+ public static List getJars(List jarNames) {
+ final List jars = jarNames.stream().map(jarName -> {
+ try (InputStream inputStream = BundlerTestHelper.class.getResourceAsStream(jarName)) {
+ if (inputStream == null) {
+ throw new IllegalArgumentException("Resource not found: " + jarName);
+ }
+
+ String fileName = Paths.get(jarName).getFileName().toString();
+ Path tempFile = Files.createTempFile("extracted-", "-" + fileName);
+ tempFile.toFile().deleteOnExit();
+
+ Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
+
+ return tempFile;
+ } catch (IOException e) {
+ throw new UncheckedIOException("Failed to copy resource to temp file", e);
+ }
+ }).toList();
+ return jars;
+ }
+
+}
diff --git a/core/src/test/resources/application-error.js b/testing/src/main/resources/application-error.js
similarity index 100%
rename from core/src/test/resources/application-error.js
rename to testing/src/main/resources/application-error.js
diff --git a/core/src/test/resources/application-mvnpm-importmap.js b/testing/src/main/resources/application-mvnpm-importmap.js
similarity index 100%
rename from core/src/test/resources/application-mvnpm-importmap.js
rename to testing/src/main/resources/application-mvnpm-importmap.js
diff --git a/core/src/test/resources/application-mvnpm.ts b/testing/src/main/resources/application-mvnpm.ts
similarity index 100%
rename from core/src/test/resources/application-mvnpm.ts
rename to testing/src/main/resources/application-mvnpm.ts
diff --git a/core/src/test/resources/application-webjar.js b/testing/src/main/resources/application-webjar.js
similarity index 100%
rename from core/src/test/resources/application-webjar.js
rename to testing/src/main/resources/application-webjar.js
diff --git a/core/src/test/resources/babel-runtime/importmap.json b/testing/src/main/resources/babel-runtime/importmap.json
similarity index 100%
rename from core/src/test/resources/babel-runtime/importmap.json
rename to testing/src/main/resources/babel-runtime/importmap.json
diff --git a/core/src/test/resources/babel-runtime/resources/_static/babel-runtime/LICENSE b/testing/src/main/resources/babel-runtime/resources/_static/babel-runtime/LICENSE
similarity index 100%
rename from core/src/test/resources/babel-runtime/resources/_static/babel-runtime/LICENSE
rename to testing/src/main/resources/babel-runtime/resources/_static/babel-runtime/LICENSE
diff --git a/core/src/test/resources/changed/application-mvnpm.js b/testing/src/main/resources/changed/application-mvnpm.js
similarity index 100%
rename from core/src/test/resources/changed/application-mvnpm.js
rename to testing/src/main/resources/changed/application-mvnpm.js
diff --git a/core/src/test/resources/logging.properties b/testing/src/main/resources/logging.properties
similarity index 100%
rename from core/src/test/resources/logging.properties
rename to testing/src/main/resources/logging.properties
diff --git a/core/src/test/resources/multi/script1.js b/testing/src/main/resources/multi/script1.js
similarity index 100%
rename from core/src/test/resources/multi/script1.js
rename to testing/src/main/resources/multi/script1.js
diff --git a/core/src/test/resources/multi/script2-test.js b/testing/src/main/resources/multi/script2-test.js
similarity index 100%
rename from core/src/test/resources/multi/script2-test.js
rename to testing/src/main/resources/multi/script2-test.js
diff --git a/core/src/test/resources/multi/style.css b/testing/src/main/resources/multi/style.css
similarity index 100%
rename from core/src/test/resources/multi/style.css
rename to testing/src/main/resources/multi/style.css
diff --git a/core/src/test/resources/multi/sub/sub.js b/testing/src/main/resources/multi/sub/sub.js
similarity index 100%
rename from core/src/test/resources/multi/sub/sub.js
rename to testing/src/main/resources/multi/sub/sub.js
diff --git a/core/src/test/resources/mvnpm/bootstrap-5.2.3.jar b/testing/src/main/resources/mvnpm/bootstrap-5.2.3.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/bootstrap-5.2.3.jar
rename to testing/src/main/resources/mvnpm/bootstrap-5.2.3.jar
diff --git a/core/src/test/resources/mvnpm/hooks-0.4.9.jar b/testing/src/main/resources/mvnpm/hooks-0.4.9.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/hooks-0.4.9.jar
rename to testing/src/main/resources/mvnpm/hooks-0.4.9.jar
diff --git a/core/src/test/resources/mvnpm/jquery-3.7.1.jar b/testing/src/main/resources/mvnpm/jquery-3.7.1.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/jquery-3.7.1.jar
rename to testing/src/main/resources/mvnpm/jquery-3.7.1.jar
diff --git a/core/src/test/resources/mvnpm/lit-3.1.0.jar b/testing/src/main/resources/mvnpm/lit-3.1.0.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/lit-3.1.0.jar
rename to testing/src/main/resources/mvnpm/lit-3.1.0.jar
diff --git a/core/src/test/resources/mvnpm/moment-2.29.4-sources.jar b/testing/src/main/resources/mvnpm/moment-2.29.4-sources.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/moment-2.29.4-sources.jar
rename to testing/src/main/resources/mvnpm/moment-2.29.4-sources.jar
diff --git a/core/src/test/resources/mvnpm/polymer-3.5.1.jar b/testing/src/main/resources/mvnpm/polymer-3.5.1.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/polymer-3.5.1.jar
rename to testing/src/main/resources/mvnpm/polymer-3.5.1.jar
diff --git a/core/src/test/resources/mvnpm/react-bootstrap-2.7.4.jar b/testing/src/main/resources/mvnpm/react-bootstrap-2.7.4.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/react-bootstrap-2.7.4.jar
rename to testing/src/main/resources/mvnpm/react-bootstrap-2.7.4.jar
diff --git a/core/src/test/resources/mvnpm/stimulus-3.2.0.jar b/testing/src/main/resources/mvnpm/stimulus-3.2.0.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/stimulus-3.2.0.jar
rename to testing/src/main/resources/mvnpm/stimulus-3.2.0.jar
diff --git a/core/src/test/resources/mvnpm/stimulus-3.2.1.jar b/testing/src/main/resources/mvnpm/stimulus-3.2.1.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/stimulus-3.2.1.jar
rename to testing/src/main/resources/mvnpm/stimulus-3.2.1.jar
diff --git a/core/src/test/resources/mvnpm/vaadin-webcomponents-24.1.6.jar b/testing/src/main/resources/mvnpm/vaadin-webcomponents-24.1.6.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/vaadin-webcomponents-24.1.6.jar
rename to testing/src/main/resources/mvnpm/vaadin-webcomponents-24.1.6.jar
diff --git a/core/src/test/resources/mvnpm/vaadin-webcomponents-24.3.5.jar b/testing/src/main/resources/mvnpm/vaadin-webcomponents-24.3.5.jar
similarity index 100%
rename from core/src/test/resources/mvnpm/vaadin-webcomponents-24.3.5.jar
rename to testing/src/main/resources/mvnpm/vaadin-webcomponents-24.3.5.jar
diff --git a/core/src/test/resources/path/baz.js b/testing/src/main/resources/path/baz.js
similarity index 100%
rename from core/src/test/resources/path/baz.js
rename to testing/src/main/resources/path/baz.js
diff --git a/core/src/test/resources/path/foo/bar.js b/testing/src/main/resources/path/foo/bar.js
similarity index 100%
rename from core/src/test/resources/path/foo/bar.js
rename to testing/src/main/resources/path/foo/bar.js
diff --git a/core/src/test/resources/path/foo/print/fob.js b/testing/src/main/resources/path/foo/print/fob.js
similarity index 100%
rename from core/src/test/resources/path/foo/print/fob.js
rename to testing/src/main/resources/path/foo/print/fob.js
diff --git a/core/src/test/resources/webjars/htmx.org-1.8.4.jar b/testing/src/main/resources/webjars/htmx.org-1.8.4.jar
similarity index 100%
rename from core/src/test/resources/webjars/htmx.org-1.8.4.jar
rename to testing/src/main/resources/webjars/htmx.org-1.8.4.jar
diff --git a/core/src/test/resources/webjars/restart__hooks-0.4.9.jar b/testing/src/main/resources/webjars/restart__hooks-0.4.9.jar
similarity index 100%
rename from core/src/test/resources/webjars/restart__hooks-0.4.9.jar
rename to testing/src/main/resources/webjars/restart__hooks-0.4.9.jar
diff --git a/testing/src/test/java/io/mvnpm/esbuild/BundlerBuildTest.java b/testing/src/test/java/io/mvnpm/esbuild/BundlerBuildTest.java
new file mode 100644
index 00000000..8b5c520b
--- /dev/null
+++ b/testing/src/test/java/io/mvnpm/esbuild/BundlerBuildTest.java
@@ -0,0 +1,67 @@
+package io.mvnpm.esbuild;
+
+import static io.mvnpm.esbuild.BundlerTestHelper.executeTest;
+import static io.mvnpm.esbuild.BundlerTestHelper.getJars;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import io.mvnpm.esbuild.model.*;
+import io.mvnpm.esbuild.model.WebDependency.WebDependencyType;
+
+public class BundlerBuildTest {
+
+ @Test
+ public void shouldBundleMvnpm() throws URISyntaxException, IOException {
+ executeTest(List.of("/mvnpm/stimulus-3.2.1.jar"), WebDependencyType.MVNPM, "application-mvnpm.js", true);
+ }
+
+ @Test
+ public void shouldBundleMvnpmSources() throws URISyntaxException, IOException {
+ executeTest(List.of("/mvnpm/moment-2.29.4-sources.jar"), WebDependencyType.MVNPM,
+ "application-mvnpm.ts", true);
+ }
+
+ @Test
+ public void shouldBundleMvnpmAndCreatePackageJson() throws URISyntaxException, IOException {
+ executeTest(List.of("/mvnpm/stimulus-3.2.0.jar"), WebDependencyType.MVNPM, "application-mvnpm.js", true);
+ }
+
+ @Test
+ public void shouldBundleMvnpmWithoutPackageJson() throws URISyntaxException, IOException {
+ executeTest(List.of("/mvnpm/polymer-3.5.1.jar"), WebDependencyType.MVNPM, "application-mvnpm-importmap.js", true);
+ }
+
+ @Test
+ public void shouldBundle() throws URISyntaxException, IOException {
+ executeTest(List.of("/webjars/htmx.org-1.8.4.jar"), WebDependencyType.WEBJARS, "application-webjar.js", true);
+ }
+
+ @Test
+ public void shouldThrowException() {
+ assertThrows(BundleException.class, () -> {
+ executeTest(List.of("/mvnpm/stimulus-3.2.1.jar"), WebDependencyType.MVNPM, "application-error.js", false);
+ });
+ }
+
+ @Test
+ public void shouldResolveRelativeFolders() throws URISyntaxException, IOException {
+ // given
+ final Path root = new File(getClass().getResource("/path/").toURI()).toPath();
+ final BundleOptions bundleOptions = BundleOptions.builder().withWorkDir(root)
+ .addAutoEntryPoint(root, "main", List.of("foo/bar.js")).build();
+
+ // when
+ final BundleResult result = Bundler.bundle(bundleOptions, true);
+
+ // then
+ assertTrue(result.dist().toFile().exists());
+ }
+
+}
diff --git a/testing/src/test/java/io/mvnpm/esbuild/BundlerDevTest.java b/testing/src/test/java/io/mvnpm/esbuild/BundlerDevTest.java
new file mode 100644
index 00000000..d31b4959
--- /dev/null
+++ b/testing/src/test/java/io/mvnpm/esbuild/BundlerDevTest.java
@@ -0,0 +1,186 @@
+package io.mvnpm.esbuild;
+
+import io.mvnpm.esbuild.model.BundleOptions;
+import io.mvnpm.esbuild.model.DevResult;
+import io.mvnpm.esbuild.model.EsBuildConfig;
+import io.mvnpm.esbuild.model.WebDependency.WebDependencyType;
+import io.mvnpm.esbuild.script.DevProcess;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static io.mvnpm.esbuild.BundlerTestHelper.getBundleOptions;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class BundlerDevTest {
+
+ @Test
+ public void shouldDev() throws URISyntaxException, IOException, InterruptedException {
+ // given
+ final BundleOptions options = getBundleOptions(List.of("/mvnpm/stimulus-3.2.1.jar"),
+ WebDependencyType.MVNPM,
+ "application-mvnpm.js").withEsConfig(EsBuildConfig.builder().fixedEntryNames().build()).build();
+
+ // when
+ AtomicReference bundleException = new AtomicReference<>();
+ final DevResult devResult = Bundler.dev(options, true);
+
+ // then
+ DevProcess process = devResult.process();
+ assertTrue(process.isAlive(), "process is alive");
+ try (process) {
+ process.build();
+ assertTrue(process.isAlive(), "process is alive");
+ final Path app = process.workDir().resolve("application-mvnpm.js");
+ assertTrue(Files.exists(app));
+ final Path distApp = process.dist().resolve("application-mvnpm.js");
+ assertTrue(Files.exists(distApp));
+
+ // when
+ Files.writeString(app, "\nalert(\"foo\");", StandardOpenOption.APPEND);
+ process.build();
+ assertTrue(process.isAlive(), "process is alive");
+ assertNull(bundleException.get(), "No error during bundling");
+ assertTrue(Files.readString(distApp).contains("alert(\"foo\");"));
+
+ }
+
+ assertFalse(process.isAlive());
+ }
+
+ @Test
+ public void shouldMultipleDevInMultipleThreads() throws URISyntaxException, IOException, InterruptedException {
+ final BundleOptions options = getBundleOptions(
+ List.of("/mvnpm/stimulus-3.2.1.jar"),
+ WebDependencyType.MVNPM,
+ "application-mvnpm.js").withEsConfig(
+ EsBuildConfig.builder()
+ .fixedEntryNames()
+ .define("foo", "\"bar")
+ .build())
+ .build();
+
+ ExecutorService executor = Executors.newFixedThreadPool(5);
+ AtomicInteger counter = new AtomicInteger(0);
+ AtomicReference r = new AtomicReference<>();
+ int targetCount = 5;
+ for (int i = 0; i < targetCount; i++) {
+ final int idx = i;
+ executor.submit(() -> {
+ System.out.println("Running task " + idx);
+ try (final DevResult result = Bundler.dev(options, true)) {
+ result.process().build();
+ r.set(result);
+ } catch (BundleException e) {
+ // good
+ counter.incrementAndGet();
+ System.out.println("good");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+ assertEquals(targetCount, counter.get());
+
+ if (r.get() != null) {
+ throw new RuntimeException(r.get().toString());
+ }
+ }
+
+ @Test
+ public void shouldDevInMultipleThreads() throws URISyntaxException, IOException, InterruptedException {
+ final BundleOptions options = getBundleOptions(
+ List.of("/mvnpm/stimulus-3.2.1.jar"),
+ WebDependencyType.MVNPM,
+ "application-mvnpm.js").withEsConfig(
+ EsBuildConfig.builder()
+ .fixedEntryNames()
+ .define("foo", "\"bar")
+ .build())
+ .build();
+
+ ExecutorService executor = Executors.newFixedThreadPool(5);
+ AtomicInteger counter = new AtomicInteger(0);
+ AtomicReference r = new AtomicReference<>();
+ int targetCount = 5;
+
+ try (final DevResult result = Bundler.dev(options, true)) {
+ for (int i = 0; i < targetCount; i++) {
+ final int idx = i;
+ executor.submit(() -> {
+ System.out.println("Running task " + idx);
+ try {
+ result.process().build();
+ r.set(result);
+ } catch (BundleException e) {
+ // good
+ counter.incrementAndGet();
+ System.out.println("good");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+ executor.shutdown();
+ executor.awaitTermination(10, TimeUnit.SECONDS);
+ }
+ assertEquals(targetCount, counter.get());
+
+ if (r.get() != null) {
+ throw new RuntimeException(r.get().toString());
+ }
+ }
+
+ @Test
+ public void shouldDevWithError() throws URISyntaxException, IOException, InterruptedException {
+
+ // given
+ final BundleOptions options = getBundleOptions(List.of("/mvnpm/stimulus-3.2.1.jar"),
+ WebDependencyType.MVNPM,
+ "application-error.js").withEsConfig(EsBuildConfig.builder().fixedEntryNames().build()).build();
+
+ // when
+ final DevResult devResult = Bundler.dev(options, true);
+
+ // then
+ DevProcess process = devResult.process();
+ assertTrue(process.isAlive(), "process is alive");
+ try (process) {
+
+ assertThrows(BundleException.class, process::build);
+ assertTrue(process.isAlive(), "process is alive");
+
+ final Path app = process.workDir().resolve("application-error.js");
+ assertTrue(Files.exists(app));
+
+ // when
+ Files.writeString(app, "alert(\"foo\");", StandardOpenOption.TRUNCATE_EXISTING);
+
+ // then
+ process.build();
+ final Path distApp = process.dist().resolve("application-error.js");
+ assertTrue(Files.exists(distApp));
+ assertTrue(Files.readString(distApp).contains("alert(\"foo\");"));
+
+ }
+ // then
+
+ }
+
+}
diff --git a/testing/src/test/java/io/mvnpm/esbuild/ScriptRunnerTest.java b/testing/src/test/java/io/mvnpm/esbuild/ScriptRunnerTest.java
new file mode 100644
index 00000000..9509ae96
--- /dev/null
+++ b/testing/src/test/java/io/mvnpm/esbuild/ScriptRunnerTest.java
@@ -0,0 +1,21 @@
+package io.mvnpm.esbuild;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+import io.mvnpm.esbuild.model.EsBuildConfigBuilder;
+import io.mvnpm.esbuild.script.ScriptRunner;
+
+public class ScriptRunnerTest {
+
+ @Test
+ public void shouldExecuteEsBuild() throws IOException {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.version();
+ Path workingDirectory = Files.createTempDirectory("testBuild");
+ new ScriptRunner(workingDirectory, esBuildConfig.build()).build();
+ }
+}
diff --git a/core/src/test/java/io/mvnpm/esbuild/install/WebDepsInstallerTest.java b/testing/src/test/java/io/mvnpm/esbuild/install/WebDepsInstallerTest.java
similarity index 100%
rename from core/src/test/java/io/mvnpm/esbuild/install/WebDepsInstallerTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/install/WebDepsInstallerTest.java
diff --git a/core/src/test/java/io/mvnpm/esbuild/model/AutoEntryPointTest.java b/testing/src/test/java/io/mvnpm/esbuild/model/AutoEntryPointTest.java
similarity index 100%
rename from core/src/test/java/io/mvnpm/esbuild/model/AutoEntryPointTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/model/AutoEntryPointTest.java
diff --git a/testing/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigToJsonTest.java b/testing/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigToJsonTest.java
new file mode 100644
index 00000000..c844b8da
--- /dev/null
+++ b/testing/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigToJsonTest.java
@@ -0,0 +1,115 @@
+package io.mvnpm.esbuild.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class EsBuildConfigToJsonTest {
+
+ @Test
+ public void shouldOutputFlagsAsJson() throws Exception {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.bundle(true);
+ esBuildConfig.format(EsBuildConfig.Format.ESM);
+
+ final String json = esBuildConfig.build().toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ assertTrue(node.get("bundle").asBoolean());
+ assertEquals("esm", node.get("format").asText());
+ }
+
+ @Test
+ public void shouldOutputLoaderFlagsAsJson() throws Exception {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.loader(Map.of(".js", EsBuildConfig.Loader.JSX, ".css", EsBuildConfig.Loader.LOCAL_CSS));
+
+ final String json = esBuildConfig.build().toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ JsonNode loaderNode = node.get("loader");
+ assertEquals("jsx", loaderNode.get(".js").asText());
+ assertEquals("local-css", loaderNode.get(".css").asText());
+ }
+
+ @Test
+ public void shouldOutputPublicPathFlagAsJson() throws Exception {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.publicPath("https://www.example.com/v1");
+
+ final String json = esBuildConfig.build().toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ assertEquals("https://www.example.com/v1", node.get("publicPath").asText());
+ }
+
+ @Test
+ public void shouldOutputStandardFlagsAsJson() throws Exception {
+ final EsBuildConfig esBuildConfig = EsBuildConfig.builder().bundle()
+ .entryPoint(new String[] { "main.js", "bundle.js" }).outDir("/tmp").minify().build();
+
+ final String json = esBuildConfig.toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ assertTrue(node.get("bundle").asBoolean());
+ assertTrue(node.get("minify").asBoolean());
+ assertEquals("/tmp", node.get("outdir").asText());
+
+ JsonNode entryPoints = node.get("entryPoints");
+ assertTrue(entryPoints.isArray());
+ assertTrue(StreamSupport.stream(entryPoints.spliterator(), false)
+ .map(JsonNode::asText)
+ .collect(Collectors.toSet())
+ .containsAll(List.of("main.js", "bundle.js")));
+ }
+
+ @Test
+ public void shouldExternalAsJson() throws Exception {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.addExternal("*.png");
+ esBuildConfig.addExternal("/images/*");
+
+ final String json = esBuildConfig.build().toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ JsonNode externalNode = node.get("external");
+ assertTrue(externalNode.isArray());
+ assertTrue(StreamSupport.stream(externalNode.spliterator(), false)
+ .map(JsonNode::asText)
+ .collect(Collectors.toSet())
+ .containsAll(List.of("*.png", "/images/*")));
+ }
+
+ @Test
+ public void shouldAddChunkNamesAsJson() throws Exception {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.chunkNames("chunks/[name]-[hash]");
+
+ final String json = esBuildConfig.build().toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ assertEquals("chunks/[name]-[hash]", node.get("chunkNames").asText());
+ }
+
+ @Test
+ public void shouldNotChangeCaseInDefineJson() throws Exception {
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.define.put("FOO", "BAR");
+ esBuildConfig.define.put("foo", "bar");
+
+ final String json = esBuildConfig.build().toJson();
+
+ JsonNode node = new ObjectMapper().readTree(json);
+ JsonNode defineNode = node.get("define");
+ assertEquals("bar", defineNode.get("foo").asText());
+ assertEquals("BAR", defineNode.get("FOO").asText()); // values are lowercased
+ }
+}
diff --git a/core/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigTest.java b/testing/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigToParamTest.java
similarity index 98%
rename from core/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigToParamTest.java
index a1ca4336..383fcff0 100644
--- a/core/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigTest.java
+++ b/testing/src/test/java/io/mvnpm/esbuild/model/EsBuildConfigToParamTest.java
@@ -8,7 +8,7 @@
import org.junit.jupiter.api.Test;
-public class EsBuildConfigTest {
+public class EsBuildConfigToParamTest {
@Test
public void shouldOutputFlags() {
diff --git a/bundle-original/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java b/testing/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
similarity index 100%
rename from bundle-original/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
rename to testing/src/test/java/io/mvnpm/esbuild/resolve/BundleTester.java
diff --git a/core/src/test/java/io/mvnpm/esbuild/resolve/DownloadResolverTest.java b/testing/src/test/java/io/mvnpm/esbuild/resolve/DownloadResolverTest.java
similarity index 100%
rename from core/src/test/java/io/mvnpm/esbuild/resolve/DownloadResolverTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/resolve/DownloadResolverTest.java
diff --git a/core/src/test/java/io/mvnpm/esbuild/util/ArchivesTest.java b/testing/src/test/java/io/mvnpm/esbuild/util/ArchivesTest.java
similarity index 100%
rename from core/src/test/java/io/mvnpm/esbuild/util/ArchivesTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/util/ArchivesTest.java
diff --git a/core/src/test/java/io/mvnpm/esbuild/util/PackageJsonTest.java b/testing/src/test/java/io/mvnpm/esbuild/util/PackageJsonTest.java
similarity index 100%
rename from core/src/test/java/io/mvnpm/esbuild/util/PackageJsonTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/util/PackageJsonTest.java
diff --git a/core/src/test/java/io/mvnpm/esbuild/util/PathUtilsTest.java b/testing/src/test/java/io/mvnpm/esbuild/util/PathUtilsTest.java
similarity index 100%
rename from core/src/test/java/io/mvnpm/esbuild/util/PathUtilsTest.java
rename to testing/src/test/java/io/mvnpm/esbuild/util/PathUtilsTest.java