Discover custom ViewModels and validate Computed bindings in shared hosts

This commit is contained in:
2026-11-13 13:27:23 +01:00
parent 5a208d2336
commit 99d93a11fc
46 changed files with 1397 additions and 64 deletions
@@ -231,7 +231,9 @@ public final class DesignerWorkflow implements AutoCloseable {
"control",
control,
"property",
property)),
property,
"resource",
worker.resource(document.document()))),
Duration.ofSeconds(15));
try (var current =
host.documents().open(document.document()).toCompletableFuture().get()) {
@@ -12,6 +12,7 @@ public final class DraftOverlay implements AutoCloseable {
private final SnapshotStore.Lease lease;
private final Path directory;
private final List<Path> runtime = new ArrayList<>();
private final Map<java.net.URI, String> resourceNames = new HashMap<>();
private final Map<String, Long> revisions = new TreeMap<>();
public DraftOverlay(SnapshotStore.Lease lease, List<DocumentSnapshot> drafts) throws Exception {
@@ -36,6 +37,7 @@ public final class DraftOverlay implements AutoCloseable {
if (matches.size() != 1)
throw new IOException("FXML draft has no unambiguous captured source root: " + file);
String name = matches.iterator().next();
resourceNames.put(draft.document(), name);
byte[] bytes = draft.text().getBytes(java.nio.charset.StandardCharsets.UTF_8);
if (bytes.length > 1024 * 1024) throw new IOException("FXML draft exceeds 1 MiB");
if (resources.putIfAbsent(name, bytes) != null)
@@ -132,6 +134,10 @@ public final class DraftOverlay implements AutoCloseable {
return List.copyOf(result);
}
public String resource(java.net.URI document) {
return Objects.requireNonNull(resourceNames.get(document), "Document is not captured");
}
public List<Path> runtime() {
return List.copyOf(runtime);
}
@@ -41,6 +41,10 @@ public final class PreviewWorker implements AutoCloseable {
return process.onExit();
}
public String resource(java.net.URI document) {
return overlay.resource(document);
}
public DesignerConfiguration.Context context() throws Exception {
return new com.fasterxml.jackson.databind.ObjectMapper()
.readValue(
@@ -104,7 +108,7 @@ public final class PreviewWorker implements AutoCloseable {
id,
process.pid(),
token,
Set.of("discover-v1", "render-rgba-v1", "layout-v1", "interactive-v1", "bindings-v2"),
Set.of("discover-v1", "render-rgba-v1", "layout-v1", "interactive-v1", "bindings-v3"),
config.requiredCapabilities());
}
drain(process.getInputStream(), log);
@@ -54,6 +54,26 @@ public final class ConnectedWorkflowContract {
&& t.property().equals("text")
&& t.status().equals("COMPATIBLE")),
"Compatible binding target discovery");
check(
bindings.viewModel().equals("fixture.components.PersonViewModel"),
"Custom ViewModel identity lost in transport");
check(
bindings.computed().stream().anyMatch(m -> m.method().equals("#greeting")),
"Computed methods lost in transport");
try (var badge =
await(host.documents().open(file.resolveSibling("BadgeCard.fxml").toUri()))) {
var metadata =
await(
workflow.bindingDetails(
false, await(badge.snapshot()), "badge", "view", "badge", "text"));
check(
metadata.controller().equals("fixture.components.BadgeCard"),
"Captured resource did not select Component Controller");
check(
metadata.viewModel().equals("fixture.components.BadgeViewModel"),
"Component ViewModel not selected");
check(metadata.problems().isEmpty(), "Component metadata rejected: " + metadata.problems());
}
var complex = await(workflow.bindings(false, initial, "home", "both"));
check(
complex.targets().stream()