Skip to content

Commit 727464d

Browse files
authored
feat: expose application properties via Options for TypeScriptBootstrapModifier consumers (#24073)
`TypeScriptBootstrapModifier` implementations (e.g., Copilot) need access to application properties to conditionally modify bootstrap TypeScript. Currently, the Copilot script is injected in dev mode regardless of whether Copilot is enabled in the project configuration. Add `withApplicationConfiguration` to `Options` and property accessor methods (`getApplicationStringProperty`, `getApplicationBooleanProperty`) that return `Optional.empty()` when configuration is unavailable (build time). Wire `ApplicationConfiguration` from `DevModeInitializer`. Fixes #24055
1 parent d951d6c commit 727464d

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/Options.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.ArrayList;
2222
import java.util.List;
2323
import java.util.Objects;
24+
import java.util.Optional;
2425
import java.util.Set;
2526

2627
import org.slf4j.LoggerFactory;
@@ -34,6 +35,7 @@
3435
import com.vaadin.flow.server.frontend.installer.NodeInstaller;
3536
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
3637
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner;
38+
import com.vaadin.flow.server.startup.ApplicationConfiguration;
3739

3840
/**
3941
* Build a <code>NodeExecutor</code> instance.
@@ -164,6 +166,8 @@ public class Options implements Serializable {
164166

165167
private boolean commercialBannerEnabled = false;
166168

169+
private ApplicationConfiguration applicationConfiguration;
170+
167171
/**
168172
* Creates a new instance.
169173
*
@@ -193,6 +197,21 @@ public Options(Lookup lookup, ClassFinder classFinder, File npmFolder) {
193197
this.npmFolder = npmFolder;
194198
}
195199

200+
/**
201+
* Sets the application configuration for the current options and returns
202+
* the updated options instance.
203+
*
204+
* @param applicationConfiguration
205+
* the application configuration to be applied
206+
* @return the updated {@code Options} instance with the specified
207+
* application configuration
208+
*/
209+
public Options withApplicationConfiguration(
210+
ApplicationConfiguration applicationConfiguration) {
211+
this.applicationConfiguration = applicationConfiguration;
212+
return this;
213+
}
214+
196215
/**
197216
* Sets the directory containing the project's frontend files
198217
*
@@ -1140,4 +1159,42 @@ public Options withMetaInfResourcesDirectory(File resourcesDirectory) {
11401159
public File getMetaInfResourcesDirectory() {
11411160
return resourcesDirectory;
11421161
}
1162+
1163+
/**
1164+
* Retrieves the value of a string application property.
1165+
* <p>
1166+
* Returns an empty {@code Optional} if the application configuration is not
1167+
* available (e.g., at build time). When configuration is available, returns
1168+
* the property value or the given default.
1169+
*
1170+
* @param name
1171+
* the name of the property to retrieve
1172+
* @param defaultValue
1173+
* the value to return if the property is not set
1174+
* @return the property value, or empty if configuration is unavailable
1175+
*/
1176+
public Optional<String> getApplicationStringProperty(String name,
1177+
String defaultValue) {
1178+
return Optional.ofNullable(applicationConfiguration)
1179+
.map(app -> app.getStringProperty(name, defaultValue));
1180+
}
1181+
1182+
/**
1183+
* Retrieves the value of a boolean application property.
1184+
* <p>
1185+
* Returns an empty {@code Optional} if the application configuration is not
1186+
* available (e.g., at build time). When configuration is available, returns
1187+
* the property value or the given default.
1188+
*
1189+
* @param name
1190+
* the name of the property to retrieve
1191+
* @param defaultValue
1192+
* the value to return if the property is not set
1193+
* @return the property value, or empty if configuration is unavailable
1194+
*/
1195+
public Optional<Boolean> getApplicationBooleanProperty(String name,
1196+
boolean defaultValue) {
1197+
return Optional.ofNullable(applicationConfiguration)
1198+
.map(app -> app.getBooleanProperty(name, defaultValue));
1199+
}
11431200
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2000-2026 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.server.frontend;
17+
18+
import java.io.File;
19+
import java.util.Optional;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.mockito.Mockito;
23+
24+
import com.vaadin.flow.server.startup.ApplicationConfiguration;
25+
import com.vaadin.tests.util.MockOptions;
26+
27+
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
import static org.junit.jupiter.api.Assertions.assertTrue;
29+
30+
class OptionsApplicationPropertiesTest {
31+
32+
@Test
33+
void getApplicationBooleanProperty_configAvailable_returnsPropertyValue() {
34+
ApplicationConfiguration config = Mockito
35+
.mock(ApplicationConfiguration.class);
36+
Mockito.when(config.getBooleanProperty("test.prop", false))
37+
.thenReturn(true);
38+
39+
Options options = new MockOptions(new File("."))
40+
.withApplicationConfiguration(config);
41+
42+
Optional<Boolean> result = options
43+
.getApplicationBooleanProperty("test.prop", false);
44+
assertEquals(Optional.of(true), result);
45+
}
46+
47+
@Test
48+
void getApplicationBooleanProperty_noConfig_returnsEmpty() {
49+
Options options = new MockOptions(new File("."));
50+
51+
Optional<Boolean> result = options
52+
.getApplicationBooleanProperty("test.prop", true);
53+
assertTrue(result.isEmpty());
54+
}
55+
56+
@Test
57+
void getApplicationStringProperty_configAvailable_returnsPropertyValue() {
58+
ApplicationConfiguration config = Mockito
59+
.mock(ApplicationConfiguration.class);
60+
Mockito.when(config.getStringProperty("test.prop", "default"))
61+
.thenReturn("custom");
62+
63+
Options options = new MockOptions(new File("."))
64+
.withApplicationConfiguration(config);
65+
66+
Optional<String> result = options
67+
.getApplicationStringProperty("test.prop", "default");
68+
assertEquals(Optional.of("custom"), result);
69+
}
70+
71+
@Test
72+
void getApplicationStringProperty_noConfig_returnsEmpty() {
73+
Options options = new MockOptions(new File("."));
74+
75+
Optional<String> result = options
76+
.getApplicationStringProperty("test.prop", "default");
77+
assertTrue(result.isEmpty());
78+
}
79+
}

vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ public static DevModeHandler initDevModeHandler(Set<Class<?>> classes,
221221
ClassFinder.class);
222222
Lookup lookup = Lookup.compose(lookupForClassFinder, lookupFromContext);
223223
Options options = new Options(lookup, baseDir)
224+
.withApplicationConfiguration(config)
224225
.withFrontendDirectory(frontendFolder)
225226
.withFrontendGeneratedFolder(
226227
new File(frontendFolder + FrontendUtils.GENERATED))

0 commit comments

Comments
 (0)