Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3202e51d7f | ||
![]() |
abc4b971d6 | ||
![]() |
eb77f0a3d7 | ||
![]() |
71f1547c6a | ||
![]() |
1b63f2807c | ||
![]() |
0c4b42e0ee | ||
![]() |
eb444dda02 | ||
![]() |
dcc1d6e53e | ||
![]() |
1d0de99e1d | ||
![]() |
b4ef7d7da3 | ||
![]() |
21e933d681 | ||
![]() |
7105686f80 | ||
![]() |
0390d15fce | ||
![]() |
9495849dc9 | ||
![]() |
f6071909b6 | ||
![]() |
2b3cd3120c | ||
![]() |
369dc51779 | ||
![]() |
148ced050b | ||
![]() |
589bbca889 | ||
![]() |
2b935da385 | ||
![]() |
7a28b0530d | ||
![]() |
45d188d064 | ||
![]() |
bd4dee98fa | ||
![]() |
1a528465f9 | ||
![]() |
5ce934b3fe | ||
![]() |
74c5698d1b | ||
![]() |
525932668f | ||
![]() |
04866b4d3a | ||
![]() |
8bc3d9d793 | ||
![]() |
55adf223d2 | ||
![]() |
22b929225f | ||
![]() |
49ead642c4 | ||
![]() |
b55cea174d |
36
.gitea/workflows/gitea-ci.yml
Normal file
36
.gitea/workflows/gitea-ci.yml
Normal file
@ -0,0 +1,36 @@
|
||||
name: Groowt Check and Publish
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Java.
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
- name: Check libraries
|
||||
run: ./gradlew check
|
||||
- name: Publish to git.jessebrault.com
|
||||
run: >
|
||||
./gradlew publishViewsPublicationToGiteaRepository &&
|
||||
./gradlew publishViewComponentsPublicationToGiteaRepository &&
|
||||
./gradlew publishWebViewComponentsPublicationToGiteaRepository &&
|
||||
./gradlew publishWebViewComponentsCompilerPublicationToGiteaRepository &&
|
||||
./gradlew publishDiPublicationToGiteaRepository &&
|
||||
./gradlew publishExtensiblePublicationToGiteaRepository &&
|
||||
./gradlew publishFpPublicationToGiteaRepository
|
||||
- name: Publish to archiva.jessebrault.com
|
||||
run: >
|
||||
./gradlew publishViewsPublicationToJbArchivaInternalRepository &&
|
||||
./gradlew publishViewComponentsPublicationToJbArchivaInternalRepository &&
|
||||
./gradlew publishWebViewComponentsPublicationToJbArchivaInternalRepository &&
|
||||
./gradlew publishWebViewComponentsCompilerPublicationToJbArchivaInternalRepository &&
|
||||
./gradlew publishDiPublicationToJbArchivaInternalRepository &&
|
||||
./gradlew publishExtensiblePublicationToJbArchivaInternalRepository &&
|
||||
./gradlew publishFpPublicationToJbArchivaInternalRepository
|
19
TODO.md
19
TODO.md
@ -20,12 +20,23 @@ For example:
|
||||
- di
|
||||
- extensible
|
||||
- fp
|
||||
- [ ] Remove gradle plugins and whatnot until we actually build the whole framework
|
||||
- [x] Remove cli, groowt-all, groowt-gradle, groowt-gradle-model.
|
||||
- [ ] Get rid of wvc compiler dependency on fp, di.
|
||||
- [ ] Remove as much cruft as possible from web-view-components-compiler, etc.
|
||||
- [ ] Use new namespaces (i.e., packages) the individual projects:
|
||||
- `com.jessebrault.groowt`: for views
|
||||
- `com.jessebrault.groowt.component`: for view-components
|
||||
- `com.jessebrault.groowt.web`: for web-view-components and web-view-components-compiler
|
||||
|
||||
## 0.1.3
|
||||
- [ ] refactor tools/gradle start scripts to use dist instead of custom bin script
|
||||
- [ ] have custom bin/* scripts which point to dist(s) for convenience
|
||||
- [ ] di bug: @Singleton toSelf() causes stack overflow
|
||||
- [ ] ~~refactor tools/gradle start scripts to use dist instead of custom bin script~~
|
||||
- [ ] ~~have custom bin/* scripts which point to dist(s) for convenience~~
|
||||
- [x] di bug: @Singleton toSelf() causes stack overflow
|
||||
- [x] wvcc bug: Nested static view classes are not seen by compiler
|
||||
- This required tweaking how the configurations are passed around. Ultimately, we should strive for less complexity
|
||||
in this regard.
|
||||
- [x] `OutletContainer` trait or interface for components which can contain an `<Outlet />` child.
|
||||
- [x] `Context` should have methods for simply finding an ancestor of a certain type without the need for a predicate.
|
||||
|
||||
## 0.1.2
|
||||
- [x] `Outlet` component for rendering children like so:
|
||||
|
@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = 'groowt'
|
||||
version = '0.1.2'
|
||||
version = '0.1.3'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -4,6 +4,8 @@ import com.jessebrault.jbarchiva.JbArchivaPlugin
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
import org.gradle.api.credentials.HttpHeaderCredentials
|
||||
import org.gradle.authentication.http.HttpHeaderAuthentication
|
||||
|
||||
class GroowtPublishPlugin implements Plugin<Project> {
|
||||
|
||||
@ -11,6 +13,25 @@ class GroowtPublishPlugin implements Plugin<Project> {
|
||||
void apply(Project project) {
|
||||
project.plugins.apply(MavenPublishPlugin)
|
||||
project.plugins.apply(JbArchivaPlugin)
|
||||
project.with {
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "Gitea"
|
||||
url = uri("https://git.jessebrault.com/api/packages/jessebrault/maven")
|
||||
|
||||
credentials(HttpHeaderCredentials) {
|
||||
name = "Authorization"
|
||||
value = "token ${System.getenv("GITEA_ACCESS_TOKEN")}"
|
||||
}
|
||||
|
||||
authentication {
|
||||
header(HttpHeaderAuthentication)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
plugins {
|
||||
id 'groowt-conventions'
|
||||
id 'groowt-logging'
|
||||
id 'groowt-publish'
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url 'https://repo.gradle.org/gradle/libs-releases'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation libs.gradle.tooling
|
||||
implementation libs.picocli
|
||||
implementation project(':groowt-gradle-model')
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes('Main-Class': 'groowt.cli.GroowtCli')
|
||||
}
|
||||
from sourceSets.main.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) }
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
dependsOn ':groowt-gradle-model:jar'
|
||||
}
|
||||
|
||||
tasks.withType(GenerateModuleMetadata).configureEach {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('groowtCli', MavenPublication) {
|
||||
artifactId = 'groowt-cli'
|
||||
from components.java
|
||||
pom {
|
||||
withXml {
|
||||
def rootNode = asNode()
|
||||
def dependenciesNode = rootNode.get('dependencies')
|
||||
rootNode.remove(dependenciesNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package groowt.cli;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public final class FileAndPathUtil {
|
||||
|
||||
public static File packageNameToFile(String packageName) {
|
||||
return new File(packageName.replace(".", File.separator));
|
||||
}
|
||||
|
||||
public static File resolve(File from, File to) {
|
||||
return from.toPath().resolve(to.toPath()).toFile();
|
||||
}
|
||||
|
||||
private FileAndPathUtil() {}
|
||||
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package groowt.cli;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Command(name = "generate", aliases = "gen", description = "Generate a component, template, model, etc.")
|
||||
public final class Generate implements Callable<Integer> {
|
||||
|
||||
@CommandLine.ParentCommand
|
||||
private GroowtCli cli;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = { "-c", "--component" },
|
||||
description = "Create a component with the given name."
|
||||
)
|
||||
private String componentName;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = { "-s", "--sourceSet" },
|
||||
description = "The source set in which to generate the component, etc.",
|
||||
defaultValue = "main"
|
||||
)
|
||||
private String sourceSet;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = { "-d", "--srcDir", "--sourceDir", "--sourceDirectory" },
|
||||
description = "The directory in the source set in which to generate the component, etc."
|
||||
)
|
||||
private File sourceDir;
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@Override
|
||||
public Integer call() {
|
||||
if (this.componentName != null) {
|
||||
GradleUtil.doWithGroowtGradleModel(this.cli.getProjectDir(), model -> {
|
||||
if (this.sourceDir == null) {
|
||||
this.sourceDir = new File(String.join(File.separator, "src", this.sourceSet, "groovy"));
|
||||
}
|
||||
final File packageDir = FileAndPathUtil.resolve(
|
||||
this.sourceDir,
|
||||
FileAndPathUtil.packageNameToFile(model.getBasePackage())
|
||||
);
|
||||
packageDir.mkdirs();
|
||||
final File componentFile = new File(packageDir, this.componentName + ".txt");
|
||||
try (final OutputStream componentFileOutputStream = new FileOutputStream(componentFile)) {
|
||||
componentFileOutputStream.write("Hello, Groowt!".getBytes());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package groowt.cli;
|
||||
|
||||
import groowt.gradle.model.GroowtGradleModel;
|
||||
import org.gradle.tooling.GradleConnector;
|
||||
import org.gradle.tooling.ProjectConnection;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class GradleUtil {
|
||||
|
||||
public static void doWith(File projectDir, Consumer<? super ProjectConnection> action) {
|
||||
final var gradleConnector = GradleConnector.newConnector().forProjectDirectory(projectDir);
|
||||
try (final var projectConnection = gradleConnector.connect()) {
|
||||
action.accept(projectConnection);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void doWith(File projectDir, Class<? extends T> modelClass, Consumer<? super T> modelConsumer) {
|
||||
doWith(projectDir, projectConnection -> {
|
||||
final T model = projectConnection.getModel(modelClass);
|
||||
modelConsumer.accept(model);
|
||||
});
|
||||
}
|
||||
|
||||
public static void doWithGroowtGradleModel(File projectDir, Consumer<? super GroowtGradleModel> modelConsumer) {
|
||||
doWith(projectDir, GroowtGradleModel.class, modelConsumer);
|
||||
}
|
||||
|
||||
private GradleUtil() {}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package groowt.cli;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@CommandLine.Command(
|
||||
name = "groowt",
|
||||
description = "The command line interface facilitating development of a Groowt project.",
|
||||
mixinStandardHelpOptions = true,
|
||||
version = "0.1.0",
|
||||
subcommands = { Generate.class }
|
||||
)
|
||||
public final class GroowtCli {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GroowtCli.class);
|
||||
|
||||
@CommandLine.Option(
|
||||
names = { "-v", "--verbose" },
|
||||
description = "Log verbosely to standard out."
|
||||
)
|
||||
private boolean verbose;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = { "--projectDir" },
|
||||
defaultValue = ".",
|
||||
description = "The root directory of the groowt project."
|
||||
)
|
||||
private File projectDir;
|
||||
|
||||
public static void main(String[] args) {
|
||||
logger.info("Hello from Groowt! Version 0.1.0");
|
||||
System.exit(new CommandLine(new GroowtCli()).execute(args));
|
||||
}
|
||||
|
||||
public boolean isVerbose() {
|
||||
return this.verbose;
|
||||
}
|
||||
|
||||
public File getProjectDir() {
|
||||
return this.projectDir;
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">
|
||||
<Appenders>
|
||||
<Console name="root">
|
||||
<PatternLayout>
|
||||
<LevelPatternSelector defaultPattern="[%t] %-5level %logger{1.} %msg%n">
|
||||
<PatternMatch key="DEBUG" pattern="[%t] %-5level %logger{1.}.%M() %msg%n"/>
|
||||
</LevelPatternSelector>
|
||||
</PatternLayout>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="INFO">
|
||||
<AppenderRef ref="root"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
@ -2,34 +2,31 @@
|
||||
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||
|
||||
[versions]
|
||||
antlr = '4.13.1'
|
||||
groovy = '4.0.21'
|
||||
junit = '5.10.2'
|
||||
kotlin = '1.9.23'
|
||||
log4j = '2.23.1'
|
||||
mockito = '5.11.0'
|
||||
slf4j = '2.0.12'
|
||||
antlr = '4.13.2'
|
||||
groovy = '4.0.25'
|
||||
junit = '5.11.4'
|
||||
kotlin = '1.9.25'
|
||||
log4j = '2.24.3'
|
||||
mockito = '5.15.2'
|
||||
slf4j = '2.0.16'
|
||||
|
||||
[libraries]
|
||||
antlr = { module = 'org.antlr:antlr4', version.ref = 'antlr' }
|
||||
antlr-runtime = { module = 'org.antlr:antlr4-runtime', version.ref = 'antlr' }
|
||||
asm = 'org.ow2.asm:asm:9.7'
|
||||
classgraph = 'io.github.classgraph:classgraph:4.8.172'
|
||||
gradle-tooling = 'org.gradle:gradle-tooling-api:8.6'
|
||||
asm = 'org.ow2.asm:asm:9.7.1'
|
||||
gradle-tooling = 'org.gradle:gradle-tooling-api:8.12.1'
|
||||
groovy = { module = 'org.apache.groovy:groovy', version.ref = 'groovy' }
|
||||
groovy-all = { module = 'org.apache.groovy:groovy-all', version.ref = 'groovy' }
|
||||
groovy-console = { module = 'org.apache.groovy:groovy-console', version.ref = 'groovy' }
|
||||
groovy-templates = { module = 'org.apache.groovy:groovy-templates', version.ref = 'groovy' }
|
||||
jakarta-inject = 'jakarta.inject:jakarta.inject-api:2.0.1'
|
||||
jansi = 'org.fusesource.jansi:jansi:2.4.1'
|
||||
jbarchiva = 'com.jessebrault.jbarchiva:jbarchiva:0.2.1'
|
||||
jetbrains-anotations = 'org.jetbrains:annotations:24.1.0'
|
||||
jbarchiva = 'com.jessebrault.jbarchiva:jbarchiva:0.2.2'
|
||||
jetbrains-anotations = 'org.jetbrains:annotations:26.0.2'
|
||||
junit-jupiter-api = { module = 'org.junit.jupiter:junit-jupiter-api', version.ref = 'junit' }
|
||||
kotlin-stdlib = { module = 'org.jetbrains.kotlin:kotlin-stdlib', version.ref = 'kotlin' }
|
||||
kotlin-test = { module = 'org.jetbrains.kotlin:kotlin-test', version.ref = 'kotlin' }
|
||||
log4j-core = { module = 'org.apache.logging.log4j:log4j-core', version.ref = 'log4j' }
|
||||
log4j-slf4jBinding = { module = 'org.apache.logging.log4j:log4j-slf4j2-impl', version.ref = 'log4j' }
|
||||
mockito-core = { module = 'org.mockito:mockito-core', version.ref = 'mockito' }
|
||||
mockito-junit = { module = 'org.mockito:mockito-junit-jupiter', version.ref = 'mockito' }
|
||||
picocli = 'info.picocli:picocli:4.7.5'
|
||||
picocli = 'info.picocli:picocli:4.7.6'
|
||||
slf4j-api = { module = 'org.slf4j:slf4j-api', version.ref = 'slf4j' }
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
6
gradlew
vendored
6
gradlew
vendored
@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@ -84,7 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
|
@ -1,23 +0,0 @@
|
||||
plugins {
|
||||
id 'groowt-conventions'
|
||||
id 'groowt-publish'
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':views')
|
||||
api project(':view-components')
|
||||
api project(':web-view-components')
|
||||
api project(':di')
|
||||
api project(':extensible')
|
||||
api project(':fp')
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('groowtAll', MavenPublication) {
|
||||
artifactId = 'groowt-all'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
plugins {
|
||||
id 'groowt-conventions'
|
||||
id 'java-library'
|
||||
id 'groowt-publish'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('groowtGradleModel', MavenPublication) {
|
||||
artifactId = 'groowt-gradle-model'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package groowt.gradle.model;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class DefaultGroowtGradleModel implements GroowtGradleModel, Serializable {
|
||||
|
||||
private String basePackage;
|
||||
private Map<String, Set<File>> sourceSetToTemplatesDirs;
|
||||
|
||||
@Override
|
||||
public String getBasePackage() {
|
||||
return this.basePackage;
|
||||
}
|
||||
|
||||
public void setBasePackage(String basePackage) {
|
||||
this.basePackage = Objects.requireNonNull(basePackage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Set<File>> getSourceSetToTemplatesDirs() {
|
||||
return Objects.requireNonNull(this.sourceSetToTemplatesDirs);
|
||||
}
|
||||
|
||||
public void setSourceFileSets(Map<String, Set<File>> sourceSetToTemplateDir) {
|
||||
this.sourceSetToTemplatesDirs = sourceSetToTemplateDir;
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package groowt.gradle.model;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface GroowtGradleModel {
|
||||
String getBasePackage();
|
||||
Map<String, Set<File>> getSourceSetToTemplatesDirs();
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
plugins {
|
||||
id 'groowt-conventions'
|
||||
id 'java-gradle-plugin'
|
||||
id 'groowt-publish'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation libs.groovy
|
||||
implementation project(':groowt-gradle-model')
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create('groowtGradle') {
|
||||
id = 'groowt-gradle'
|
||||
implementationClass = 'groowt.gradle.GroowtGradlePlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('groowtGradlePlugin', MavenPublication) {
|
||||
artifactId = 'groowt-gradle'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DefaultGroowtExtension implements GroowtExtension {
|
||||
|
||||
private final Property<String> basePackage;
|
||||
|
||||
@Inject
|
||||
public DefaultGroowtExtension(ObjectFactory objectFactory) {
|
||||
this.basePackage = objectFactory.property(String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property<String> getBasePackage() {
|
||||
return this.basePackage;
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import org.gradle.api.file.SourceDirectorySet;
|
||||
import org.gradle.api.internal.file.DefaultSourceDirectorySet;
|
||||
import org.gradle.api.internal.tasks.TaskDependencyFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DefaultTemplateSourceDirectorySet extends DefaultSourceDirectorySet implements TemplateSourceDirectorySet {
|
||||
|
||||
@Inject
|
||||
public DefaultTemplateSourceDirectorySet(
|
||||
SourceDirectorySet delegate,
|
||||
TaskDependencyFactory taskDependencyFactory
|
||||
) {
|
||||
super(delegate, taskDependencyFactory);
|
||||
}
|
||||
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.file.SourceDirectorySet;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.reflect.HasPublicType;
|
||||
import org.gradle.api.reflect.TypeOf;
|
||||
import org.gradle.util.internal.ConfigureUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class DefaultTemplateSourceSet implements TemplateSourceSet, HasPublicType {
|
||||
|
||||
private final TemplateSourceDirectorySet templateSourceDirectorySet;
|
||||
private final SourceDirectorySet allTemplates;
|
||||
|
||||
@Inject
|
||||
public DefaultTemplateSourceSet(ObjectFactory objectFactory, String name, String displayName) {
|
||||
this.templateSourceDirectorySet = objectFactory.newInstance(
|
||||
DefaultTemplateSourceDirectorySet.class,
|
||||
objectFactory.sourceDirectorySet(name, displayName + " ComponentTemplate sources")
|
||||
);
|
||||
this.templateSourceDirectorySet.getFilter().include("**/*.wvc", "**/*.gst");
|
||||
this.allTemplates = objectFactory.sourceDirectorySet(
|
||||
"all" + name,
|
||||
displayName + " ComponentTemplate sources"
|
||||
);
|
||||
this.allTemplates.source(this.templateSourceDirectorySet);
|
||||
this.allTemplates.getFilter().include("**/*.wvc", "**/*.gst");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeOf<?> getPublicType() {
|
||||
return TypeOf.typeOf(TemplateSourceSet.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateSourceDirectorySet getTemplates() {
|
||||
return this.templateSourceDirectorySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateSourceSet templates(Action<? super TemplateSourceDirectorySet> action) {
|
||||
action.execute(this.templateSourceDirectorySet);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public TemplateSourceSet templates(Closure closure) {
|
||||
ConfigureUtil.configure(closure, this.templateSourceDirectorySet);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceDirectorySet getAllTemplates() {
|
||||
return this.allTemplates;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
public interface GroowtExtension {
|
||||
Property<String> getBasePackage();
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import groowt.gradle.model.GroowtGradleModelBuilder;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.internal.tasks.DefaultSourceSet;
|
||||
import org.gradle.api.plugins.GroovyPlugin;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.gradle.api.internal.lambdas.SerializableLambdas.spec;
|
||||
|
||||
public class GroowtGradlePlugin implements Plugin<Project> {
|
||||
|
||||
private final ToolingModelBuilderRegistry modelBuilderRegistry;
|
||||
|
||||
@Inject
|
||||
public GroowtGradlePlugin(ToolingModelBuilderRegistry modelBuilderRegistry) {
|
||||
this.modelBuilderRegistry = modelBuilderRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
// Apply java and groovy plugins, if not done already
|
||||
final var pluginManager = project.getPluginManager();
|
||||
pluginManager.apply(JavaPlugin.class);
|
||||
pluginManager.apply(GroovyPlugin.class);
|
||||
|
||||
// Create our groowt configuration for storing the groowt dependencies
|
||||
final Provider<Configuration> groowtConfigurationProvider = project.getConfigurations()
|
||||
.register("groowt", configuration -> {
|
||||
configuration.setCanBeConsumed(false);
|
||||
configuration.setCanBeResolved(true);
|
||||
});
|
||||
|
||||
// Create groowt extension and source sets.
|
||||
final GroowtExtension groowtExtension = project.getExtensions().create(
|
||||
GroowtExtension.class,
|
||||
"groowt",
|
||||
DefaultGroowtExtension.class
|
||||
);
|
||||
groowtExtension.getBasePackage().convention("");
|
||||
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
final SourceSetContainer javaSourceSets = javaExtension.getSourceSets();
|
||||
|
||||
// data resources, such as texts, json files, sqlite-databases, etc.
|
||||
javaSourceSets.getByName("main", mainSourceSet -> {
|
||||
mainSourceSet.getResources().srcDir("src/data");
|
||||
});
|
||||
|
||||
// TODO: figure out how we can set the compile behavior for all of these.
|
||||
javaSourceSets.forEach(sourceSet -> {
|
||||
final TemplateSourceSet templateSourceSet = project.getObjects().newInstance(
|
||||
DefaultTemplateSourceSet.class,
|
||||
"wvc",
|
||||
((DefaultSourceSet) sourceSet).getDisplayName()
|
||||
);
|
||||
final TemplateSourceDirectorySet templateSourceDirectorySet = templateSourceSet.getTemplates();
|
||||
sourceSet.getExtensions().add(
|
||||
TemplateSourceDirectorySet.class,
|
||||
"templates",
|
||||
templateSourceDirectorySet
|
||||
);
|
||||
templateSourceDirectorySet.srcDir("src/" + sourceSet.getName() + "/templates");
|
||||
|
||||
// Explicitly capture only a FileCollection in the lambda below for compatibility with configuration-cache.
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
final FileCollection templateSourceFiles = templateSourceDirectorySet;
|
||||
sourceSet.getResources().getFilter().exclude(
|
||||
spec(element -> templateSourceFiles.contains(element.getFile()))
|
||||
);
|
||||
sourceSet.getAllJava().source(templateSourceDirectorySet);
|
||||
sourceSet.getAllSource().source(templateSourceDirectorySet);
|
||||
});
|
||||
|
||||
// create init task
|
||||
project.getTasks().create("groowtInit", GroowtInitTask.class, groowtConfigurationProvider);
|
||||
|
||||
// tooling models for cli
|
||||
this.modelBuilderRegistry.register(new GroowtGradleModelBuilder());
|
||||
}
|
||||
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.*;
|
||||
import java.util.Set;
|
||||
|
||||
public class GroowtInitTask extends DefaultTask {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GroowtInitTask.class);
|
||||
|
||||
private static final Set<String> srcDirsToMake = Set.of("groovy", "templates");
|
||||
|
||||
private final Provider<Configuration> groowtConfigurationProvider;
|
||||
private final File binDir;
|
||||
private final File groowtDir;
|
||||
|
||||
@Inject
|
||||
public GroowtInitTask(Project project, Provider<Configuration> groowtConfigurationProvider) {
|
||||
this.groowtConfigurationProvider = groowtConfigurationProvider;
|
||||
this.binDir = new File(project.getRootDir(), "bin");
|
||||
this.groowtDir = new File(project.getRootDir(), "groowt");
|
||||
}
|
||||
|
||||
protected void createBin() throws IOException {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
this.binDir.mkdirs();
|
||||
final var groowtFile = new File(this.binDir, "groowt");
|
||||
try (final InputStream bootstrapInputStream = this.getClass().getResourceAsStream("groowt")) {
|
||||
if (bootstrapInputStream != null) {
|
||||
try (final OutputStream bootstrapOutputStream = new FileOutputStream(groowtFile)) {
|
||||
bootstrapInputStream.transferTo(bootstrapOutputStream);
|
||||
}
|
||||
if (!groowtFile.setExecutable(true)) {
|
||||
logger.warn("Could not set bin/groowt to executable; you will have to do this yourself.");
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Could not find groowt shell script.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void createGroowtFolder() throws IOException {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
this.groowtDir.mkdirs();
|
||||
final var groowtConfiguration = this.groowtConfigurationProvider.get();
|
||||
final Set<File> groowtCliFiles = groowtConfiguration.files(dependency -> {
|
||||
final var group = dependency.getGroup();
|
||||
if (group == null || !group.equals("groowt")) {
|
||||
return false;
|
||||
} else {
|
||||
return dependency.getName().equals("groowt-cli");
|
||||
}
|
||||
});
|
||||
final File groowtCliJarFile = groowtCliFiles.stream()
|
||||
.filter(file -> file.getName().endsWith(".jar"))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("Could not find groowt-cli jar file."));
|
||||
final File groowtCliJarOutputFile = new File(this.groowtDir, "groowt-cli.jar");
|
||||
try (final InputStream groowtCliJarInputStream = new FileInputStream(groowtCliJarFile)) {
|
||||
try (final OutputStream groowtCliJarOutputStream = new FileOutputStream(groowtCliJarOutputFile)) {
|
||||
groowtCliJarInputStream.transferTo(groowtCliJarOutputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void createSrcDirs() {
|
||||
final var javaPluginExtension = this.getProject().getExtensions().getByType(JavaPluginExtension.class);
|
||||
javaPluginExtension.getSourceSets().forEach(sourceSet -> {
|
||||
final var srcDirs = sourceSet.getAllSource().getSrcDirs();
|
||||
srcDirs.forEach(srcDir -> {
|
||||
if (!sourceSet.getName().contains("test") && srcDirsToMake.contains(srcDir.getName())) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
srcDir.mkdirs();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
public void doInit() throws IOException {
|
||||
this.createBin();
|
||||
this.createGroowtFolder();
|
||||
this.createSrcDirs();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import org.gradle.api.file.SourceDirectorySet;
|
||||
|
||||
public interface TemplateSourceDirectorySet extends SourceDirectorySet {}
|
@ -1,18 +0,0 @@
|
||||
package groowt.gradle;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.file.SourceDirectorySet;
|
||||
|
||||
public interface TemplateSourceSet {
|
||||
|
||||
TemplateSourceDirectorySet getTemplates();
|
||||
|
||||
SourceDirectorySet getAllTemplates();
|
||||
|
||||
TemplateSourceSet templates(Action<? super TemplateSourceDirectorySet> action);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
TemplateSourceSet templates(Closure closure);
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package groowt.gradle.model;
|
||||
|
||||
import groowt.gradle.GroowtExtension;
|
||||
import groowt.gradle.TemplateSourceDirectorySet;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class GroowtGradleModelBuilder implements ToolingModelBuilder {
|
||||
|
||||
@Override
|
||||
public boolean canBuild(String modelName) {
|
||||
return modelName.equals(GroowtGradleModel.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Object buildAll(@NotNull String modelName, Project project) {
|
||||
final DefaultGroowtGradleModel model = new DefaultGroowtGradleModel();
|
||||
final var groowtExtension = project.getExtensions().getByType(GroowtExtension.class);
|
||||
|
||||
// base package
|
||||
final Property<String> basePackage = groowtExtension.getBasePackage();
|
||||
if (!basePackage.isPresent()) {
|
||||
throw new RuntimeException(
|
||||
"The property 'basePackage' must be set under the 'groowt' extension in build.gradle"
|
||||
);
|
||||
}
|
||||
model.setBasePackage(basePackage.get());
|
||||
|
||||
// templates dirs
|
||||
final Map<String, Set<File>> sourceSetToTemplatesDirs = new HashMap<>();
|
||||
final var javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
javaExtension.getSourceSets().forEach(sourceSet -> {
|
||||
final TemplateSourceDirectorySet templateSourceDirectorySet =
|
||||
sourceSet.getExtensions().getByType(TemplateSourceDirectorySet.class);
|
||||
sourceSetToTemplatesDirs.put(sourceSet.getName(), templateSourceDirectorySet.getFiles());
|
||||
});
|
||||
model.setSourceFileSets(sourceSetToTemplatesDirs);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
java -jar groowt/groowt-cli.jar "$@"
|
@ -6,8 +6,7 @@ pluginManagement {
|
||||
|
||||
rootProject.name = 'groowt'
|
||||
|
||||
include 'cli', 'groowt-all', 'groowt-gradle', 'groowt-gradle-model', 'views', 'view-components',
|
||||
'web-view-components', 'web-view-components-compiler'
|
||||
include 'views', 'view-components', 'web-view-components', 'web-view-components-compiler'
|
||||
|
||||
file('util').eachDir {
|
||||
include it.name
|
||||
|
@ -24,7 +24,7 @@ jar {
|
||||
publishing {
|
||||
publications {
|
||||
create('di', MavenPublication) {
|
||||
artifactId = 'groowt-util-di'
|
||||
artifactId = 'util-di'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
@ -3,31 +3,58 @@ package groowt.util.di;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class DefaultRegistry implements Registry {
|
||||
|
||||
protected record ClassKeyBinding<T>(Class<T> key, Binding<T> binding) {}
|
||||
protected static class BindingContainer {
|
||||
|
||||
protected final Collection<ClassKeyBinding<?>> classBindings = new ArrayList<>();
|
||||
private final Map<Class<?>, Binding<?>> bindings = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> @Nullable Binding<T> get(Class<T> key) {
|
||||
for (final var entry : bindings.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(key)) {
|
||||
return (Binding<T>) entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> void put(Class<T> key, Binding<T> binding) {
|
||||
this.bindings.put(key, binding);
|
||||
}
|
||||
|
||||
public void remove(Class<?> key) {
|
||||
this.bindings.remove(key);
|
||||
}
|
||||
|
||||
public <T> void removeIf(Class<T> key, Predicate<? super Binding<T>> filter) {
|
||||
if (filter.test(this.get(key))) {
|
||||
this.bindings.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.bindings.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final BindingContainer bindingContainer = new BindingContainer();
|
||||
protected final Collection<RegistryExtension> extensions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void removeBinding(Class<?> key) {
|
||||
this.classBindings.removeIf(classKeyBinding -> classKeyBinding.key().equals(key));
|
||||
this.bindingContainer.remove(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> void removeBindingIf(Class<T> key, Predicate<Binding<T>> filter) {
|
||||
this.classBindings.removeIf(classKeyBinding ->
|
||||
classKeyBinding.key().equals(key) && filter.test((Binding<T>) classKeyBinding.binding())
|
||||
);
|
||||
this.bindingContainer.removeIf(key, filter);
|
||||
}
|
||||
|
||||
private <E extends RegistryExtension> List<E> getAllRegistryExtensions(Class<E> extensionType) {
|
||||
@ -117,18 +144,12 @@ public class DefaultRegistry implements Registry {
|
||||
public <T> void bind(Class<T> key, Consumer<? super BindingConfigurator<T>> configure) {
|
||||
final var configurator = new SimpleBindingConfigurator<>(key);
|
||||
configure.accept(configurator);
|
||||
this.classBindings.add(new ClassKeyBinding<>(key, configurator.getBinding()));
|
||||
this.bindingContainer.put(key, configurator.getBinding());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @Nullable <T> Binding<T> getBinding(Class<T> key) {
|
||||
for (final var classKeyBinding : this.classBindings) {
|
||||
if (key.isAssignableFrom(classKeyBinding.key())) {
|
||||
return (Binding<T>) classKeyBinding.binding();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public <T> @Nullable Binding<T> getBinding(Class<T> key) {
|
||||
return this.bindingContainer.get(key);
|
||||
}
|
||||
|
||||
private KeyBinder<?> findKeyBinder(Class<?> keyClass) {
|
||||
@ -189,7 +210,7 @@ public class DefaultRegistry implements Registry {
|
||||
|
||||
@Override
|
||||
public void clearAllBindings() {
|
||||
this.classBindings.clear();
|
||||
this.bindingContainer.clear();
|
||||
for (final var extension : this.extensions) {
|
||||
if (extension instanceof KeyBinder<?> keyBinder) {
|
||||
keyBinder.clearAllBindings();
|
||||
|
@ -1,8 +1,9 @@
|
||||
package groowt.util.di;
|
||||
|
||||
import jakarta.inject.Provider;
|
||||
import jakarta.inject.Singleton;
|
||||
|
||||
import static groowt.util.di.BindingUtil.toSingleton;
|
||||
import static groowt.util.di.BindingUtil.toLazySingleton;
|
||||
|
||||
public final class SingletonScopeHandler implements ScopeHandler<Singleton> {
|
||||
|
||||
@ -19,12 +20,22 @@ public final class SingletonScopeHandler implements ScopeHandler<Singleton> {
|
||||
RegistryObjectFactory objectFactory
|
||||
) {
|
||||
final Binding<T> potentialBinding = this.owner.getBinding(dependencyClass);
|
||||
if (potentialBinding != null) {
|
||||
return potentialBinding;
|
||||
} else {
|
||||
this.owner.bind(dependencyClass, toSingleton(objectFactory.createInstance(dependencyClass)));
|
||||
return this.owner.getBinding(dependencyClass);
|
||||
return switch (potentialBinding) {
|
||||
case ClassBinding<T>(Class<T> from, Class<? extends T> to) -> {
|
||||
this.owner.bind(from, toLazySingleton(() -> objectFactory.createInstance(to)));
|
||||
yield this.owner.getBinding(from);
|
||||
}
|
||||
case ProviderBinding<T>(Class<T> from, Provider<? extends T> provider) -> {
|
||||
this.owner.bind(from, toLazySingleton(provider::get));
|
||||
yield this.owner.getBinding(from);
|
||||
}
|
||||
case SingletonBinding<T> singletonBinding -> singletonBinding;
|
||||
case LazySingletonBinding<T> lazySingletonBinding -> lazySingletonBinding;
|
||||
case null -> {
|
||||
this.owner.bind(dependencyClass, toLazySingleton(() -> objectFactory.createInstance(dependencyClass)));
|
||||
yield this.owner.getBinding(dependencyClass);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,6 +2,7 @@ package groowt.util.di;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static groowt.util.di.BindingUtil.*;
|
||||
@ -250,4 +251,25 @@ public class DefaultRegistryObjectFactoryTests {
|
||||
assertEquals("Given Greeting", g.greet());
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static final class SingletonGreeter implements Greeter {
|
||||
|
||||
@Override
|
||||
public String greet() {
|
||||
return "Hello, World!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singletonDoesNotOverflow() {
|
||||
final var b = DefaultRegistryObjectFactory.Builder.withDefaults();
|
||||
b.configureRegistry(r -> {
|
||||
r.bind(SingletonGreeter.class, toSelf());
|
||||
});
|
||||
final var f = b.build();
|
||||
final var g = f.get(SingletonGreeter.class);
|
||||
assertEquals("Hello, World!", g.greet());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ jar {
|
||||
publishing {
|
||||
publications {
|
||||
create('extensible', MavenPublication) {
|
||||
artifactId = 'groowt-util-extensible'
|
||||
artifactId = 'util-extensible'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ jar {
|
||||
publishing {
|
||||
publications {
|
||||
create('fp', MavenPublication) {
|
||||
artifactId = 'groowt-util-fp'
|
||||
artifactId = 'util-fp'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,14 @@ java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'groowt-view-components'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('viewComponents', MavenPublication) {
|
||||
artifactId = 'groowt-view-components'
|
||||
artifactId = 'view-components'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
@ -10,41 +10,8 @@ public abstract class CachingComponentTemplateCompiler<U extends ComponentTempla
|
||||
|
||||
private final Map<Class<? extends ViewComponent>, ComponentTemplateCompileResult> cache = new HashMap<>();
|
||||
|
||||
// private ComponentTemplate instantiate(
|
||||
// GroovyClassLoader groovyClassLoader,
|
||||
// CompileResult compileResult
|
||||
// ) {
|
||||
// for (final var groovyClass : compileResult.otherClasses()) {
|
||||
// // Try to find it. If we can't, we need to load it via the groovy loader
|
||||
// try {
|
||||
// Class.forName(groovyClass.getName(), true, groovyClassLoader);
|
||||
// } catch (ClassNotFoundException ignored) {
|
||||
// groovyClassLoader.defineClass(groovyClass.getName(), groovyClass.getBytes());
|
||||
// } catch (LinkageError ignored) {
|
||||
// // no-op, because we already have it
|
||||
// }
|
||||
// }
|
||||
// final GroovyClass templateGroovyClass = compileResult.templateClass();
|
||||
// Class<?> templateClass;
|
||||
// // Try to find it. If we can't, we need to load it via the groovy loader
|
||||
// try {
|
||||
// templateClass = Class.forName(templateGroovyClass.getName(), true, groovyClassLoader);
|
||||
// } catch (ClassNotFoundException ignored) {
|
||||
// templateClass = groovyClassLoader.defineClass(
|
||||
// templateGroovyClass.getName(),
|
||||
// templateGroovyClass.getBytes()
|
||||
// );
|
||||
// }
|
||||
// try {
|
||||
// return (ComponentTemplate) templateClass.getConstructor().newInstance();
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException("Unable to instantiate ComponentTemplate " + templateClass.getName(), e);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public final ComponentTemplateCompileResult compile(U compileUnit)
|
||||
throws ComponentTemplateCompileException {
|
||||
public final ComponentTemplateCompileResult compile(U compileUnit) throws ComponentTemplateCompileException {
|
||||
if (this.cache.containsKey(compileUnit.getForClass())) {
|
||||
return this.cache.get(compileUnit.getForClass());
|
||||
} else {
|
||||
|
@ -4,16 +4,9 @@ import groowt.view.component.ViewComponent;
|
||||
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||
|
||||
public interface ComponentTemplateCompileUnit {
|
||||
|
||||
String getDescriptiveName();
|
||||
Class<? extends ViewComponent> getForClass();
|
||||
String getDefaultPackageName();
|
||||
ComponentTemplateSource getSource();
|
||||
ComponentTemplateCompileResult compile(ComponentTemplateCompilerConfiguration configuration)
|
||||
throws ComponentTemplateCompileException;
|
||||
|
||||
default ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException {
|
||||
return this.compile(new DefaultComponentTemplateCompilerConfiguration());
|
||||
}
|
||||
|
||||
ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException;
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package groowt.view.component.compiler;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
|
||||
public interface ComponentTemplateCompilerConfiguration {
|
||||
GroovyClassLoader getGroovyClassLoader();
|
||||
CompilerConfiguration getGroovyCompilerConfiguration();
|
||||
CompilePhase getToCompilePhase();
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package groowt.view.component.compiler;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class DefaultComponentTemplateCompilerConfiguration implements ComponentTemplateCompilerConfiguration {
|
||||
|
||||
private GroovyClassLoader groovyClassLoader;
|
||||
private CompilerConfiguration groovyCompilerConfiguration;
|
||||
private CompilePhase toCompilePhase;
|
||||
|
||||
public DefaultComponentTemplateCompilerConfiguration() {
|
||||
this.groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
this.groovyCompilerConfiguration = new CompilerConfiguration();
|
||||
this.toCompilePhase = CompilePhase.CLASS_GENERATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroovyClassLoader getGroovyClassLoader() {
|
||||
return this.groovyClassLoader;
|
||||
}
|
||||
|
||||
public void setGroovyClassLoader(GroovyClassLoader groovyClassLoader) {
|
||||
this.groovyClassLoader = requireNonNull(groovyClassLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerConfiguration getGroovyCompilerConfiguration() {
|
||||
return this.groovyCompilerConfiguration;
|
||||
}
|
||||
|
||||
public void setGroovyCompilerConfiguration(CompilerConfiguration groovyCompilerConfiguration) {
|
||||
this.groovyCompilerConfiguration = requireNonNull(groovyCompilerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilePhase getToCompilePhase() {
|
||||
return this.toCompilePhase;
|
||||
}
|
||||
|
||||
public void setToCompilePhase(CompilePhase toCompilePhase) {
|
||||
this.toCompilePhase = requireNonNull(toCompilePhase);
|
||||
}
|
||||
|
||||
}
|
@ -99,6 +99,23 @@ public interface ComponentContext {
|
||||
return ancestorClass.cast(this.findNearestAncestor(matching.and(ancestorClass::isInstance)));
|
||||
}
|
||||
|
||||
default <T extends ViewComponent> @Nullable T findNearestAncestor(Class<T> ancestorClass) {
|
||||
return ancestorClass.cast(this.findNearestAncestor(ancestorClass::isInstance));
|
||||
}
|
||||
|
||||
boolean hasAncestor(Predicate<? super ViewComponent> matching);
|
||||
|
||||
default <T extends ViewComponent> boolean hasAncestor(
|
||||
Class<T> ancestorClass,
|
||||
Predicate<? super ViewComponent> matching
|
||||
) {
|
||||
return this.hasAncestor(matching.and(ancestorClass::isInstance));
|
||||
}
|
||||
|
||||
default <T extends ViewComponent> boolean hasAncestor(Class<T> ancestorClass) {
|
||||
return this.hasAncestor(ancestorClass::isInstance);
|
||||
}
|
||||
|
||||
List<ViewComponent> getAllAncestors();
|
||||
|
||||
}
|
||||
|
@ -70,7 +70,10 @@ public class DefaultComponentContext implements ComponentContext {
|
||||
public @Nullable ViewComponent findNearestAncestor(Predicate<? super ViewComponent> matching) {
|
||||
final List<ViewComponent> componentStack = this.getRenderContext().getComponentStack();
|
||||
if (componentStack.size() > 1) {
|
||||
for (final var ancestor : componentStack.subList(1, componentStack.size() -1)) {
|
||||
// 1/27/25: earlier this was originally componentStack.size() - 1 as the second argument to sublist().
|
||||
// On examination today, it didn't make sense, because it would be chopping off the farthest ancestor from
|
||||
// search. So I removed it, in accordance with the implementation in hasAncestor().
|
||||
for (final var ancestor : componentStack.subList(1, componentStack.size())) {
|
||||
if (matching.test(ancestor)) {
|
||||
return ancestor;
|
||||
}
|
||||
@ -79,6 +82,19 @@ public class DefaultComponentContext implements ComponentContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAncestor(Predicate<? super ViewComponent> matching) {
|
||||
final List<ViewComponent> componentStack = this.getRenderContext().getComponentStack();
|
||||
if (componentStack.size() > 1) {
|
||||
for (final var ancestor : componentStack.subList(1, componentStack.size())) {
|
||||
if (matching.test(ancestor)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewComponent> getAllAncestors() {
|
||||
final List<ViewComponent> componentStack = this.getRenderContext().getComponentStack();
|
||||
|
@ -25,10 +25,14 @@ java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'groowt-views'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('views', MavenPublication) {
|
||||
artifactId = 'groowt-views'
|
||||
artifactId = 'views'
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,9 @@ tasks.register('uberJar', Jar) {
|
||||
group 'groovyc'
|
||||
archiveBaseName = 'web-view-components-uber'
|
||||
from sourceSets.main.output
|
||||
from sourceSets.main.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) }
|
||||
from sourceSets.main.runtimeClasspath
|
||||
.filter(File.&exists)
|
||||
.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
@ -217,6 +219,10 @@ tasks.named('sourcesJar', Jar) {
|
||||
dependsOn 'generateAllAntlr'
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'groowt-web-view-components-compiler'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('webViewComponentsCompiler', MavenPublication) {
|
||||
|
@ -4,14 +4,15 @@ if [ "$1" == "--debug" ]; then
|
||||
shift
|
||||
gradle -q uberJar && \
|
||||
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 \
|
||||
-cp build/libs/web-view-components-uber-0.1.0.jar \
|
||||
-cp build/libs/web-view-components-uber-0.1.2.jar \
|
||||
org.codehaus.groovy.tools.FileSystemCompiler \
|
||||
--configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \
|
||||
-d groovyc-out \
|
||||
"$@"
|
||||
else
|
||||
gradle -q uberJar && \
|
||||
groovyc -cp build/libs/web-view-components-uber-0.1.0.jar \
|
||||
java -cp build/libs/web-view-components-uber-0.1.2.jar \
|
||||
org.codehaus.groovy.tools.FileSystemCompiler \
|
||||
--configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \
|
||||
-d groovyc-out \
|
||||
"$@"
|
||||
|
@ -0,0 +1 @@
|
||||
<Echo>Hello, World!</Echo>
|
@ -4,7 +4,6 @@ import groowt.view.component.compiler.*;
|
||||
import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
import groowt.view.component.web.transpile.DefaultGroovyTranspiler;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.tools.GroovyClass;
|
||||
@ -16,25 +15,12 @@ public class DefaultWebViewComponentTemplateCompiler
|
||||
extends CachingComponentTemplateCompiler<WebViewComponentTemplateCompileUnit>
|
||||
implements WebViewComponentTemplateCompiler {
|
||||
|
||||
private final ComponentTemplateCompilerConfiguration configuration;
|
||||
private final WebViewComponentTemplateCompilerConfiguration configuration;
|
||||
|
||||
public DefaultWebViewComponentTemplateCompiler(ComponentTemplateCompilerConfiguration configuration) {
|
||||
public DefaultWebViewComponentTemplateCompiler(WebViewComponentTemplateCompilerConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
protected WebViewComponentTemplateCompileException getException(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
ParserRuleContext parserRuleContext
|
||||
) {
|
||||
final var exception = new WebViewComponentTemplateCompileException(
|
||||
compileUnit,
|
||||
"Parser error: " + parserRuleContext.exception.getMessage(),
|
||||
parserRuleContext.exception
|
||||
);
|
||||
exception.setParserRuleContext(parserRuleContext);
|
||||
return exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentTemplateCompileResult doCompile(WebViewComponentTemplateCompileUnit compileUnit)
|
||||
throws ComponentTemplateCompileException {
|
||||
@ -49,22 +35,12 @@ public class DefaultWebViewComponentTemplateCompiler
|
||||
: "AnonymousWebViewComponent" + System.nanoTime();
|
||||
final var templateClassSimpleName = ownerComponentName + "Template";
|
||||
|
||||
final SourceUnit sourceUnit = transpiler.transpile(
|
||||
this.configuration,
|
||||
compileUnit,
|
||||
cuNode,
|
||||
templateClassSimpleName
|
||||
);
|
||||
final SourceUnit sourceUnit = transpiler.transpile(compileUnit, cuNode, templateClassSimpleName);
|
||||
compileUnit.getGroovyCompilationUnit().addSource(sourceUnit);
|
||||
|
||||
// set the groovy compile unit's class loader to the configuration's classloader.
|
||||
compileUnit.getGroovyCompilationUnit().setClassLoader(
|
||||
this.configuration.getGroovyClassLoader()
|
||||
);
|
||||
|
||||
// compile groovy
|
||||
try {
|
||||
compileUnit.getGroovyCompilationUnit().compile(this.configuration.getToCompilePhase().getPhaseNumber());
|
||||
compileUnit.getGroovyCompilationUnit().compile(this.configuration.getCompilePhase().getPhaseNumber());
|
||||
} catch (CompilationFailedException compilationFailedException) {
|
||||
throw new WebViewComponentTemplateCompileException(
|
||||
compileUnit,
|
||||
|
@ -1,11 +1,9 @@
|
||||
package groowt.view.component.web.compiler;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
|
||||
public class DefaultWebViewComponentTemplateCompilerFactory implements WebViewComponentTemplateCompilerFactory {
|
||||
|
||||
@Override
|
||||
public WebViewComponentTemplateCompiler create(ComponentTemplateCompilerConfiguration configuration) {
|
||||
public WebViewComponentTemplateCompiler create(WebViewComponentTemplateCompilerConfiguration configuration) {
|
||||
return new DefaultWebViewComponentTemplateCompiler(configuration);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package groowt.view.component.web.groovyc;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||
import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
@ -80,13 +79,12 @@ public class DelegatingWebViewComponentTemplateParserPlugin implements ParserPlu
|
||||
}
|
||||
|
||||
final var groovyTranspiler = new DefaultGroovyTranspiler();
|
||||
final String teplateClassSimpleName = sourceUnitFileName.substring(0, sourceUnitFileName.length() - 4);
|
||||
final String templateClassName = sourceUnitFileName.substring(0, sourceUnitFileName.length() - 4);
|
||||
try {
|
||||
final SourceUnit transpiledSourceUnit = groovyTranspiler.transpile(
|
||||
new DefaultComponentTemplateCompilerConfiguration(),
|
||||
compileUnit,
|
||||
cuNode,
|
||||
teplateClassSimpleName
|
||||
templateClassName
|
||||
);
|
||||
return transpiledSourceUnit.getAST();
|
||||
} catch (ComponentTemplateCompileException e) {
|
||||
|
@ -6,7 +6,6 @@ import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.ast.node.*;
|
||||
import groowt.view.component.web.transpile.groovy.GroovyUtil;
|
||||
import groowt.view.component.web.transpile.groovy.GroovyUtil.ConvertResult;
|
||||
import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver;
|
||||
import groowt.view.component.web.util.SourcePosition;
|
||||
import org.codehaus.groovy.ast.*;
|
||||
import org.codehaus.groovy.ast.expr.*;
|
||||
@ -15,7 +14,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static groowt.view.component.web.transpile.TranspilerUtil.*;
|
||||
|
||||
@ -25,13 +23,9 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
private static final ClassNode COMPONENT_RESOLVE_EXCEPTION_TYPE = ClassHelper.make(ComponentResolveException.class);
|
||||
private static final ClassNode COMPONENT_CREATE_EXCEPTION_TYPE = ClassHelper.make(ComponentCreateException.class);
|
||||
|
||||
private static final Pattern isFqn = Pattern.compile("^(\\p{Ll}.+\\.)+\\p{Lu}.+$");
|
||||
private static final Pattern isWithPackage = Pattern.compile("^\\p{Ll}.+\\.");
|
||||
|
||||
private LeftShiftFactory leftShiftFactory;
|
||||
private ValueNodeTranspiler valueNodeTranspiler;
|
||||
private BodyTranspiler bodyTranspiler;
|
||||
private ComponentClassNodeResolver componentClassNodeResolver;
|
||||
|
||||
public void setLeftShiftFactory(LeftShiftFactory leftShiftFactory) {
|
||||
this.leftShiftFactory = leftShiftFactory;
|
||||
@ -45,10 +39,6 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
this.bodyTranspiler = bodyTranspiler;
|
||||
}
|
||||
|
||||
public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) {
|
||||
this.componentClassNodeResolver = componentClassNodeResolver;
|
||||
}
|
||||
|
||||
/* UTIL */
|
||||
|
||||
protected String getComponentName(int componentNumber) {
|
||||
@ -74,49 +64,14 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
|
||||
/* RESOLVE */
|
||||
|
||||
protected List<Expression> getArgsAsList(
|
||||
TypedComponentNode componentNode,
|
||||
TranspilerState state
|
||||
) {
|
||||
protected List<Expression> getArgsAsList(TypedComponentNode componentNode) {
|
||||
return switch (componentNode.getArgs().getType()) {
|
||||
case ClassComponentTypeNode classComponentTypeNode -> {
|
||||
final String identifier = classComponentTypeNode.getIdentifier();
|
||||
final ConstantExpression alias = getStringLiteral(identifier);
|
||||
final var matcher = isFqn.matcher(identifier);
|
||||
if (matcher.matches()) {
|
||||
final ClassNode classNode = ClassHelper.make(identifier);
|
||||
final ClassExpression classExpression = new ClassExpression(classNode);
|
||||
final var classExpression = new ClassExpression(classNode);
|
||||
yield List.of(alias, classExpression);
|
||||
} else {
|
||||
// we need to resolve it
|
||||
final var isWithPackageMatcher = isWithPackage.matcher(identifier);
|
||||
if (isWithPackageMatcher.matches()) {
|
||||
final var resolveResult = this.componentClassNodeResolver.getClassForFqn(identifier);
|
||||
if (resolveResult.isLeft()) {
|
||||
final var error = resolveResult.getLeft();
|
||||
error.setNode(componentNode.getArgs().getType());
|
||||
state.addError(error);
|
||||
yield List.of();
|
||||
} else {
|
||||
final ClassNode classNode = resolveResult.getRight();
|
||||
final ClassExpression classExpression = new ClassExpression(classNode); // TODO: pos
|
||||
yield List.of(alias, classExpression);
|
||||
}
|
||||
} else {
|
||||
final var resolveResult =
|
||||
this.componentClassNodeResolver.getClassForNameWithoutPackage(identifier);
|
||||
if (resolveResult.isLeft()) {
|
||||
final var error = resolveResult.getLeft();
|
||||
error.setNode(componentNode.getArgs().getType());
|
||||
state.addError(error);
|
||||
yield List.of();
|
||||
} else {
|
||||
final ClassNode classNode = resolveResult.getRight();
|
||||
final ClassExpression classExpression = new ClassExpression(classNode); // TODO: pos
|
||||
yield List.of(alias, classExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case StringComponentTypeNode stringComponentTypeNode -> {
|
||||
final String identifier = stringComponentTypeNode.getIdentifier();
|
||||
@ -127,8 +82,8 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
}
|
||||
|
||||
// 'h1' | 'MyComponent', MyComponent(.class)
|
||||
protected ArgumentListExpression getResolveArgs(TypedComponentNode componentNode, TranspilerState state) {
|
||||
final List<Expression> args = this.getArgsAsList(componentNode, state);
|
||||
protected ArgumentListExpression getResolveArgs(TypedComponentNode componentNode) {
|
||||
final List<Expression> args = this.getArgsAsList(componentNode);
|
||||
final ArgumentListExpression argsListExpr = new ArgumentListExpression();
|
||||
args.forEach(argsListExpr::addExpression);
|
||||
return argsListExpr;
|
||||
@ -142,7 +97,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
return new MethodCallExpression(
|
||||
new VariableExpression(state.getRenderContext()),
|
||||
"resolve",
|
||||
this.getResolveArgs(componentNode, state)
|
||||
this.getResolveArgs(componentNode)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package groowt.view.component.web.transpile;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileUnit;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.web.ast.node.BodyNode;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
import groowt.view.component.web.ast.node.PreambleNode;
|
||||
@ -10,7 +9,6 @@ import groowt.view.component.web.compiler.MultipleWebViewComponentCompileErrorsE
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import groowt.view.component.web.transpile.groovy.GroovyUtil;
|
||||
import groowt.view.component.web.transpile.resolve.ClassLoaderComponentClassNodeResolver;
|
||||
import org.codehaus.groovy.ast.*;
|
||||
import org.codehaus.groovy.ast.expr.*;
|
||||
import org.codehaus.groovy.ast.stmt.BlockStatement;
|
||||
@ -31,25 +29,13 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultGroovyTranspiler.class);
|
||||
|
||||
protected TranspilerConfiguration getConfiguration(
|
||||
ClassLoaderComponentClassNodeResolver classLoaderComponentClassNodeResolver
|
||||
) {
|
||||
return SimpleTranspilerConfiguration.withDefaults(classLoaderComponentClassNodeResolver);
|
||||
}
|
||||
|
||||
protected void addAutomaticImports(WebViewComponentModuleNode moduleNode, TranspilerConfiguration configuration) {
|
||||
configuration.getImports().forEach(moduleNode::addImport);
|
||||
configuration.getStaticImports().forEach(staticImport -> moduleNode.addStaticImport(
|
||||
staticImport.getV1(), staticImport.getV2(), staticImport.getV3()
|
||||
));
|
||||
configuration.getStarImports().forEach(moduleNode::addStarImport);
|
||||
configuration.getStaticStarImports().forEach(moduleNode::addStaticStarImport);
|
||||
protected TranspilerConfiguration getConfiguration() {
|
||||
return SimpleTranspilerConfiguration.withDefaults();
|
||||
}
|
||||
|
||||
protected WebViewComponentModuleNode initModuleNode(
|
||||
ComponentTemplateCompileUnit compileUnit,
|
||||
WebViewComponentSourceUnit sourceUnit,
|
||||
TranspilerConfiguration configuration
|
||||
WebViewComponentSourceUnit sourceUnit
|
||||
) {
|
||||
final var moduleNode = new WebViewComponentModuleNode(sourceUnit);
|
||||
sourceUnit.setModuleNode(moduleNode);
|
||||
@ -59,22 +45,16 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
moduleNode.setPackageName(defaultPackageName);
|
||||
}
|
||||
|
||||
this.addAutomaticImports(moduleNode, configuration);
|
||||
return moduleNode;
|
||||
}
|
||||
|
||||
protected ClassNode initMainClassNode(
|
||||
ComponentTemplateCompileUnit compileUnit,
|
||||
String templateClassName,
|
||||
WebViewComponentModuleNode moduleNode
|
||||
) {
|
||||
protected ClassNode initMainClassNode(ComponentTemplateCompileUnit compileUnit, String templateClassName) {
|
||||
final ClassNode mainClassNode = new ClassNode(
|
||||
compileUnit.getDefaultPackageName() + templateClassName,
|
||||
ACC_PUBLIC,
|
||||
ClassHelper.OBJECT_TYPE
|
||||
);
|
||||
mainClassNode.addInterface(TranspilerUtil.COMPONENT_TEMPLATE);
|
||||
moduleNode.addClass(mainClassNode);
|
||||
return mainClassNode;
|
||||
}
|
||||
|
||||
@ -216,40 +196,32 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
|
||||
@Override
|
||||
public WebViewComponentSourceUnit transpile(
|
||||
ComponentTemplateCompilerConfiguration compilerConfiguration,
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
CompilationUnitNode compilationUnitNode,
|
||||
String templateClassSimpleName
|
||||
) throws ComponentTemplateCompileException {
|
||||
// resolver, transpilerConfiguration, and positionSetter
|
||||
final ClassLoaderComponentClassNodeResolver resolver = new ClassLoaderComponentClassNodeResolver(
|
||||
compileUnit,
|
||||
compilerConfiguration.getGroovyClassLoader()
|
||||
);
|
||||
final var transpilerConfiguration = this.getConfiguration(resolver);
|
||||
// transpilerConfiguration, and positionSetter
|
||||
final var transpilerConfiguration = this.getConfiguration();
|
||||
final PositionSetter positionSetter = transpilerConfiguration.getPositionSetter();
|
||||
|
||||
// prepare sourceUnit
|
||||
final CompilerConfiguration groovyCompilerConfiguration =
|
||||
compilerConfiguration.getGroovyCompilerConfiguration();
|
||||
final CompilerConfiguration groovyCompilerConfiguration = compileUnit.getGroovyCompilationUnit()
|
||||
.getConfiguration();
|
||||
final WebViewComponentSourceUnit sourceUnit = new WebViewComponentSourceUnit(
|
||||
compileUnit.getDescriptiveName(),
|
||||
compileUnit.getGroovyReaderSource(),
|
||||
groovyCompilerConfiguration,
|
||||
compilerConfiguration.getGroovyClassLoader(),
|
||||
compileUnit.getGroovyCompilationUnit().getClassLoader(),
|
||||
new ErrorCollector(groovyCompilerConfiguration)
|
||||
);
|
||||
|
||||
// prepare moduleNode
|
||||
final WebViewComponentModuleNode moduleNode = this.initModuleNode(
|
||||
compileUnit, sourceUnit, transpilerConfiguration
|
||||
compileUnit, sourceUnit
|
||||
);
|
||||
|
||||
// set resolver's moduleNode
|
||||
resolver.setModuleNode(moduleNode);
|
||||
|
||||
// prepare mainClassNode
|
||||
final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName, moduleNode);
|
||||
final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName);
|
||||
|
||||
// handle preamble
|
||||
final PreambleNode preambleNode = compilationUnitNode.getPreambleNode();
|
||||
@ -257,6 +229,9 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
this.handlePreamble(templateClassSimpleName, preambleNode, mainClassNode, moduleNode, positionSetter);
|
||||
}
|
||||
|
||||
// Moved here so that moduleNode#getMainClassName reflects fqn of mainClassName
|
||||
moduleNode.addClass(mainClassNode);
|
||||
|
||||
// getRenderer method and render closure
|
||||
// first, getRenderer params
|
||||
final Parameter componentContextParam = new Parameter(COMPONENT_CONTEXT_TYPE, COMPONENT_CONTEXT_NAME);
|
||||
|
@ -1,14 +1,12 @@
|
||||
package groowt.view.component.web.transpile;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
|
||||
public interface GroovyTranspiler {
|
||||
|
||||
WebViewComponentSourceUnit transpile(
|
||||
ComponentTemplateCompilerConfiguration compilerConfiguration,
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
CompilationUnitNode compilationUnitNode,
|
||||
String templateClassSimpleName
|
||||
|
@ -1,7 +1,6 @@
|
||||
package groowt.view.component.web.transpile;
|
||||
|
||||
import groovy.lang.Tuple3;
|
||||
import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
import java.util.Map;
|
||||
@ -12,9 +11,8 @@ import static groowt.view.component.web.transpile.TranspilerUtil.*;
|
||||
|
||||
public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
|
||||
public static TranspilerConfiguration withDefaults(ComponentClassNodeResolver componentClassNodeResolver) {
|
||||
public static TranspilerConfiguration withDefaults() {
|
||||
final var c = new SimpleTranspilerConfiguration();
|
||||
c.setComponentClassNodeResolver(componentClassNodeResolver);
|
||||
|
||||
final var ct = new DefaultComponentTranspiler();
|
||||
final PositionSetter ps = new SimplePositionSetter();
|
||||
@ -27,7 +25,6 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
ct.setLeftShiftFactory(lsf);
|
||||
ct.setBodyTranspiler(bt);
|
||||
ct.setValueNodeTranspiler(vnt);
|
||||
ct.setComponentClassNodeResolver(componentClassNodeResolver);
|
||||
|
||||
c.setComponentTranspiler(ct);
|
||||
c.setPositionSetter(ps);
|
||||
@ -40,7 +37,6 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
return c;
|
||||
}
|
||||
|
||||
private ComponentClassNodeResolver componentClassNodeResolver;
|
||||
private ComponentTranspiler componentTranspiler;
|
||||
private PositionSetter positionSetter;
|
||||
private LeftShiftFactory leftShiftFactory;
|
||||
@ -49,14 +45,6 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
private BodyTranspiler bodyTranspiler;
|
||||
private ValueNodeTranspiler valueNodeTranspiler;
|
||||
|
||||
public ComponentClassNodeResolver getComponentClassNodeResolver() {
|
||||
return Objects.requireNonNull(this.componentClassNodeResolver);
|
||||
}
|
||||
|
||||
public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) {
|
||||
this.componentClassNodeResolver = componentClassNodeResolver;
|
||||
}
|
||||
|
||||
public ComponentTranspiler getComponentTranspiler() {
|
||||
return Objects.requireNonNull(this.componentTranspiler);
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.WebViewComponent;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CachingComponentClassNodeResolver implements ComponentClassNodeResolver {
|
||||
|
||||
private final List<ClassNode> classNodes = new ArrayList<>();
|
||||
|
||||
protected final WebViewComponentTemplateCompileUnit compileUnit;
|
||||
|
||||
public CachingComponentClassNodeResolver(WebViewComponentTemplateCompileUnit compileUnit) {
|
||||
this.compileUnit = compileUnit;
|
||||
}
|
||||
|
||||
public void addClass(Class<? extends WebViewComponent> clazz) {
|
||||
this.classNodes.add(ClassHelper.make(clazz));
|
||||
}
|
||||
|
||||
public void addClassNode(ClassNode classNode) {
|
||||
this.classNodes.add(classNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForFqn(String fqn) {
|
||||
for (final var classNode : this.classNodes) {
|
||||
if (classNode.getName().equals(fqn)) {
|
||||
return Either.right(classNode);
|
||||
}
|
||||
}
|
||||
return Either.left(new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
fqn,
|
||||
"Could not resolve ClassNode for fqn: " + fqn,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForNameWithoutPackage(String nameWithoutPackage) {
|
||||
for (final var classNode : this.classNodes) {
|
||||
if (classNode.getNameWithoutPackage().equals(nameWithoutPackage)) {
|
||||
return Either.right(classNode);
|
||||
}
|
||||
}
|
||||
return Either.left(new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
nameWithoutPackage,
|
||||
"Could not resolve ClassNode for nameWithoutPackage: " + nameWithoutPackage,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ClassLoaderComponentClassNodeResolver extends ModuleNodeComponentClassNodeResolver {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModuleNodeComponentClassNodeResolver.class);
|
||||
|
||||
protected final ClassLoader classLoader;
|
||||
|
||||
public ClassLoaderComponentClassNodeResolver(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
ClassLoader classLoader
|
||||
) {
|
||||
super(compileUnit);
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
protected final Either<ClassNodeResolveException, ClassNode> resolveWithClassLoader(String fqn) {
|
||||
logger.debug("Trying to resolve {}", fqn);
|
||||
try {
|
||||
Class<?> clazz = this.classLoader.loadClass(ResolveUtil.convertCanonicalNameToBinaryName(fqn));
|
||||
final var classNode = ResolveUtil.getClassNode(clazz);
|
||||
return Either.right(classNode);
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
return Either.left(
|
||||
new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
fqn,
|
||||
"Could not find class " + fqn + " with classLoader " +
|
||||
this.classLoader,
|
||||
classNotFoundException
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForFqn(String fqn) {
|
||||
return super.getClassForFqn(fqn).flatMapLeft(ignored -> {
|
||||
final var classLoaderResult = this.resolveWithClassLoader(fqn);
|
||||
if (classLoaderResult.isRight()) {
|
||||
this.addClassNode(classLoaderResult.getRight());
|
||||
}
|
||||
return classLoaderResult;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
public interface ComponentClassNodeResolver {
|
||||
|
||||
final class ClassNodeResolveException extends WebViewComponentTemplateCompileException {
|
||||
|
||||
private final String identifier;
|
||||
|
||||
public ClassNodeResolveException(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
String identifier,
|
||||
String message
|
||||
) {
|
||||
super(compileUnit, message);
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public ClassNodeResolveException(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
String identifier,
|
||||
String message,
|
||||
Throwable cause
|
||||
) {
|
||||
super(compileUnit, message, cause);
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Either<ClassNodeResolveException, ClassNode> getClassForFqn(String fqn);
|
||||
Either<ClassNodeResolveException, ClassNode> getClassForNameWithoutPackage(String nameWithoutPackage);
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ModuleNodeComponentClassNodeResolver extends CachingComponentClassNodeResolver {
|
||||
|
||||
private ModuleNode moduleNode;
|
||||
|
||||
public ModuleNodeComponentClassNodeResolver(WebViewComponentTemplateCompileUnit compileUnit) {
|
||||
super(compileUnit);
|
||||
}
|
||||
|
||||
public ModuleNode getModuleNode() {
|
||||
return Objects.requireNonNull(this.moduleNode);
|
||||
}
|
||||
|
||||
public void setModuleNode(ModuleNode moduleNode) {
|
||||
this.moduleNode = Objects.requireNonNull(moduleNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForNameWithoutPackage(String nameWithoutPackage) {
|
||||
return super.getClassForNameWithoutPackage(nameWithoutPackage).flatMapLeft(ignored -> {
|
||||
// try regular imports first
|
||||
final var importedClassNode = this.getModuleNode().getImportType(nameWithoutPackage);
|
||||
if (importedClassNode != null) {
|
||||
this.addClassNode(importedClassNode);
|
||||
return Either.right(importedClassNode);
|
||||
}
|
||||
|
||||
// try star imports
|
||||
final var starImports = this.getModuleNode().getStarImports();
|
||||
for (final var starImport : starImports) {
|
||||
final var packageName = starImport.getPackageName();
|
||||
final String fqn;
|
||||
if (!packageName.equals(".") && packageName.endsWith(".")) {
|
||||
fqn = packageName + nameWithoutPackage;
|
||||
} else {
|
||||
fqn = packageName + "." + nameWithoutPackage;
|
||||
}
|
||||
final var withPackage = this.getClassForFqn(fqn);
|
||||
if (withPackage.isRight()) {
|
||||
return withPackage;
|
||||
}
|
||||
}
|
||||
|
||||
// try pre-pending package and asking for fqn
|
||||
final String moduleNodePackageName = this.getModuleNode().getPackageName();
|
||||
final String packageName;
|
||||
if (moduleNodePackageName != null) {
|
||||
packageName = moduleNodePackageName;
|
||||
} else {
|
||||
packageName = "";
|
||||
}
|
||||
|
||||
final String fqn;
|
||||
if (packageName.equals(".") || packageName.isEmpty()) {
|
||||
fqn = nameWithoutPackage;
|
||||
} else if (packageName.endsWith(".")) {
|
||||
fqn = packageName + nameWithoutPackage;
|
||||
} else {
|
||||
fqn = packageName + "." + nameWithoutPackage;
|
||||
}
|
||||
|
||||
final var withPackage = this.getClassForFqn(fqn);
|
||||
if (withPackage.isRight()) {
|
||||
return withPackage;
|
||||
} else {
|
||||
return Either.left(new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
nameWithoutPackage,
|
||||
"Cannot resolve " + nameWithoutPackage
|
||||
+ " from imports, package-local classes, or pre-added classes."
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class ResolveUtil {
|
||||
|
||||
private static final Pattern packageSplitter = Pattern.compile("^(?<package>(?>\\p{Ll}[^.]*\\.)*)(?<top>\\p{Lu}[^.]*)(?<members>(?>\\.\\p{Lu}[^.]*)*)$");
|
||||
|
||||
public static ClassNode getClassNode(Class<?> clazz) {
|
||||
return ClassHelper.makeCached(clazz);
|
||||
}
|
||||
|
||||
public static String convertCanonicalNameToBinaryName(String canonicalName) {
|
||||
final var matcher = packageSplitter.matcher(canonicalName);
|
||||
if (matcher.matches()) {
|
||||
return new StringBuilder()
|
||||
.append(matcher.group("package"))
|
||||
.append(matcher.group("top"))
|
||||
.append(matcher.group("members").replaceAll("\\.", "\\$"))
|
||||
.toString();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot split apart " + canonicalName);
|
||||
}
|
||||
}
|
||||
|
||||
private ResolveUtil() {}
|
||||
|
||||
}
|
@ -1,5 +1,16 @@
|
||||
package groowt.view.component.web.groovyc
|
||||
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer
|
||||
|
||||
(configuration as CompilerConfiguration).tap {
|
||||
pluginFactory = new WebViewComponentParserPluginFactory()
|
||||
addCompilationCustomizers(new ImportCustomizer().tap {
|
||||
addStarImports(
|
||||
"groowt.view.component.web.lib",
|
||||
"groowt.view.component.web.runtime",
|
||||
"groowt.view.component.runtime"
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
(configuration as CompilerConfiguration).pluginFactory = new WebViewComponentParserPluginFactory()
|
||||
|
@ -3,7 +3,6 @@ package groowt.view.component.web.transpiler;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import groowt.view.component.web.transpile.SimpleTranspilerConfiguration;
|
||||
import groowt.view.component.web.transpile.TranspilerConfiguration;
|
||||
import groowt.view.component.web.transpile.resolve.CachingComponentClassNodeResolver;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
|
||||
public class DefaultBodyTranspilerTests extends BodyTranspilerTests {
|
||||
@ -13,7 +12,7 @@ public class DefaultBodyTranspilerTests extends BodyTranspilerTests {
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
ModuleNode moduleNode
|
||||
) {
|
||||
return SimpleTranspilerConfiguration.withDefaults(new CachingComponentClassNodeResolver(compileUnit));
|
||||
return SimpleTranspilerConfiguration.withDefaults();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package groowt.view.component.web.transpiler;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static groowt.view.component.web.transpile.resolve.ResolveUtil.convertCanonicalNameToBinaryName;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ResolveUtilTests {
|
||||
|
||||
@Test
|
||||
public void abcABC() {
|
||||
assertEquals("a.b.c.A$B$C", convertCanonicalNameToBinaryName("a.b.c.A.B.C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ABC() {
|
||||
assertEquals("A$B$C", convertCanonicalNameToBinaryName("A.B.C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void abcA() {
|
||||
assertEquals("a.b.c.A", convertCanonicalNameToBinaryName("a.b.c.A"));
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,6 @@ package groowt.view.component.web.transpiler;
|
||||
|
||||
import groovy.lang.Tuple2;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.compiler.source.StringSource;
|
||||
import groowt.view.component.web.BaseWebViewComponent;
|
||||
import groowt.view.component.web.antlr.ParserUtil;
|
||||
@ -55,7 +54,6 @@ public abstract class GroovyTranspilerTests {
|
||||
final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||
try {
|
||||
this.transpiler.transpile(
|
||||
new DefaultComponentTemplateCompilerConfiguration(),
|
||||
new DefaultWebViewComponentTemplateCompileUnit(
|
||||
"<anonymous string source>",
|
||||
AnonymousWebViewComponent.class,
|
||||
|
@ -1,8 +1,10 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
VERSION="0.1.2"
|
||||
|
||||
if [ "\$1" == "--debug" ]; then
|
||||
shift
|
||||
gradle -q toolsJar && java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 -cp build/libs/web-view-components-compiler-tools-0.1.1.jar $mainClassName "\$@"
|
||||
gradle -q toolsJar && java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 -cp build/libs/web-view-components-compiler-tools-\$VERSION.jar $mainClassName "\$@"
|
||||
else
|
||||
gradle -q toolsJar && java -cp build/libs/web-view-components-compiler-tools-0.1.1.jar $mainClassName "\$@"
|
||||
gradle -q toolsJar && java -cp build/libs/web-view-components-compiler-tools-\$VERSION.jar $mainClassName "\$@"
|
||||
fi
|
||||
|
@ -9,6 +9,7 @@ import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.CompilationUnit;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@ -71,6 +72,15 @@ public final class GroovyWvcCompiler implements Callable<Integer> {
|
||||
|
||||
public Integer doCompile() {
|
||||
final CompilerConfiguration configuration = new CompilerConfiguration();
|
||||
|
||||
final var addGroowtImports = new ImportCustomizer();
|
||||
addGroowtImports.addStarImports(
|
||||
"groowt.view.component.web.lib",
|
||||
"groowt.view.component.web.runtime",
|
||||
"groowt.view.component.runtime"
|
||||
);
|
||||
configuration.addCompilationCustomizers(addGroowtImports);
|
||||
|
||||
configuration.setPluginFactory(new WebViewComponentParserPluginFactory());
|
||||
final CompilationUnit compilationUnit = new CompilationUnit(configuration);
|
||||
|
||||
|
@ -133,6 +133,10 @@ java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName = 'groowt-web-view-components'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create('webViewComponents', MavenPublication) {
|
||||
|
@ -5,7 +5,6 @@ import groowt.view.component.ComponentRenderException
|
||||
import groowt.view.component.context.ComponentContext
|
||||
import groowt.view.component.context.ComponentScope.TypeAndFactory
|
||||
import groowt.view.component.factory.ComponentFactory
|
||||
import groowt.view.component.web.WithHtml
|
||||
|
||||
class IntrinsicHtml extends DelegatingWebViewComponent implements WithHtml {
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package groowt.view.component.web.lib
|
||||
|
||||
import groowt.view.View
|
||||
import groowt.view.component.ComponentRenderException
|
||||
import groowt.view.component.runtime.DefaultComponentWriter
|
||||
|
||||
class Outlet extends DelegatingWebViewComponent {
|
||||
@ -14,6 +15,11 @@ class Outlet extends DelegatingWebViewComponent {
|
||||
@Override
|
||||
protected View getDelegate() {
|
||||
return { Writer w ->
|
||||
if (!context.hasAncestor(OutletContainer)) {
|
||||
throw new ComponentRenderException(
|
||||
"<Outlet> is being used outside of a component implementing OutletContainer."
|
||||
)
|
||||
}
|
||||
def cw = new DefaultComponentWriter(w, context.renderContext, context)
|
||||
givenChildren.each { cw << it }
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package groowt.view.component.web.lib
|
||||
|
||||
import groowt.view.component.web.WebViewComponent
|
||||
|
||||
interface OutletContainer extends WebViewComponent {}
|
@ -1,4 +1,4 @@
|
||||
package groowt.view.component.web
|
||||
package groowt.view.component.web.lib
|
||||
|
||||
trait WithHtml {
|
||||
|
@ -4,13 +4,14 @@ import groowt.view.component.ViewComponent;
|
||||
import groowt.view.component.compiler.AbstractComponentTemplateCompileUnit;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileResult;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||
import groowt.view.component.compiler.source.FileSource;
|
||||
import groowt.view.component.compiler.source.URISource;
|
||||
import groowt.view.component.compiler.source.URLSource;
|
||||
import org.codehaus.groovy.control.CompilationUnit;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.Janitor;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import org.codehaus.groovy.control.io.ReaderSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -20,8 +21,20 @@ import java.net.URI;
|
||||
public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponentTemplateCompileUnit
|
||||
implements ReaderSource, WebViewComponentTemplateCompileUnit {
|
||||
|
||||
private static CompilationUnit getCompilationUnit() {
|
||||
final var configuration = new CompilerConfiguration();
|
||||
final var addGroowtImports = new ImportCustomizer();
|
||||
addGroowtImports.addStarImports(
|
||||
"groowt.view.component.web.lib",
|
||||
"groowt.view.component.web.runtime",
|
||||
"groowt.view.component.runtime"
|
||||
);
|
||||
configuration.addCompilationCustomizers(addGroowtImports);
|
||||
return new CompilationUnit(configuration);
|
||||
}
|
||||
|
||||
private final String defaultPackageName;
|
||||
private final CompilationUnit groovyCompilationUnit = new CompilationUnit();
|
||||
private final CompilationUnit groovyCompilationUnit;
|
||||
|
||||
public DefaultWebViewComponentTemplateCompileUnit(
|
||||
String descriptiveName,
|
||||
@ -35,6 +48,7 @@ public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponen
|
||||
} else {
|
||||
this.defaultPackageName = defaultPackageName;
|
||||
}
|
||||
this.groovyCompilationUnit = getCompilationUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,9 +67,8 @@ public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponen
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentTemplateCompileResult compile(ComponentTemplateCompilerConfiguration configuration)
|
||||
throws ComponentTemplateCompileException {
|
||||
final WebViewComponentTemplateCompiler compiler = WebViewComponentTemplateCompiler.get(configuration);
|
||||
public ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException {
|
||||
final WebViewComponentTemplateCompiler compiler = WebViewComponentTemplateCompiler.get();
|
||||
return compiler.compile(this);
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,10 @@ public interface WebViewComponentTemplateCompiler
|
||||
extends ComponentTemplateCompiler<WebViewComponentTemplateCompileUnit> {
|
||||
|
||||
static WebViewComponentTemplateCompiler get() {
|
||||
return get(new DefaultComponentTemplateCompilerConfiguration());
|
||||
return get(new WebViewComponentTemplateCompilerConfiguration());
|
||||
}
|
||||
|
||||
static WebViewComponentTemplateCompiler get(ComponentTemplateCompilerConfiguration configuration) {
|
||||
static WebViewComponentTemplateCompiler get(WebViewComponentTemplateCompilerConfiguration configuration) {
|
||||
final ServiceLoader<WebViewComponentTemplateCompilerFactory> factoryServiceLoader =
|
||||
ServiceLoader.load(WebViewComponentTemplateCompilerFactory.class);
|
||||
final var factory = factoryServiceLoader.findFirst()
|
||||
|
@ -0,0 +1,17 @@
|
||||
package groowt.view.component.web.compiler;
|
||||
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
|
||||
public class WebViewComponentTemplateCompilerConfiguration {
|
||||
|
||||
private CompilePhase compilePhase = CompilePhase.CLASS_GENERATION;
|
||||
|
||||
public CompilePhase getCompilePhase() {
|
||||
return this.compilePhase;
|
||||
}
|
||||
|
||||
public void setCompilePhase(CompilePhase compilePhase) {
|
||||
this.compilePhase = compilePhase;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package groowt.view.component.web.compiler;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
|
||||
public interface WebViewComponentTemplateCompilerFactory {
|
||||
WebViewComponentTemplateCompiler create(ComponentTemplateCompilerConfiguration configuration);
|
||||
WebViewComponentTemplateCompiler create(WebViewComponentTemplateCompilerConfiguration configuration);
|
||||
}
|
||||
|
@ -1,17 +1,35 @@
|
||||
package groowt.view.component.web.lib
|
||||
|
||||
|
||||
import groowt.view.component.web.WebViewComponentContext
|
||||
import groowt.view.component.web.WebViewComponentScope
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class OutletTests extends AbstractWebViewComponentTests {
|
||||
|
||||
static final class DummyOutletContainer extends Echo implements OutletContainer {
|
||||
|
||||
DummyOutletContainer() {
|
||||
super([:])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void configureContext(WebViewComponentContext context) {
|
||||
context.configureRootScope(WebViewComponentScope) {
|
||||
addWithNoArgConstructor(DummyOutletContainer)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void smokeScreen() {
|
||||
doTest('<Outlet />', '')
|
||||
doTest('<OutletTests.DummyOutletContainer><Outlet /></OutletTests.DummyOutletContainer>', '')
|
||||
}
|
||||
|
||||
@Test
|
||||
void withChildren() {
|
||||
doTest('<Echo items={[0, 1, 2]}><Outlet children={items} /></Echo>', '012')
|
||||
doTest('<OutletTests.DummyOutletContainer><Echo items={[0, 1, 2]}><Outlet children={items} /></Echo></OutletTests.DummyOutletContainer>', '012')
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user