Compare commits
	
		
			No commits in common. "2b935da385e99fe156fbc5f3f67eee2f30d172f3" and "04866b4d3a0f724ca0328dcfd6dfe610d37304e4" have entirely different histories.
		
	
	
		
			2b935da385
			...
			04866b4d3a
		
	
		
							
								
								
									
										9
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								TODO.md
									
									
									
									
									
								
							| @ -24,12 +24,9 @@ For example: | |||||||
| - [ ] Get rid of wvc compiler dependency on di | - [ ] Get rid of wvc compiler dependency on di | ||||||
| 
 | 
 | ||||||
| ## 0.1.3 | ## 0.1.3 | ||||||
| - [ ] ~~refactor tools/gradle start scripts to use dist instead of custom bin script~~ | - [ ] refactor tools/gradle start scripts to use dist instead of custom bin script | ||||||
|   - [ ] ~~have custom bin/* scripts which point to dist(s) for convenience~~ |   - [ ] have custom bin/* scripts which point to dist(s) for convenience | ||||||
| - [x] di bug: @Singleton toSelf() causes stack overflow | - [ ] 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. |  | ||||||
| - [ ] `OutletContainer` trait or interface for components which can contain an `<Outlet />` child. | - [ ] `OutletContainer` trait or interface for components which can contain an `<Outlet />` child. | ||||||
| - [ ] `Context` should have methods for simply finding an ancestor of a certain type without the need for a predicate. | - [ ] `Context` should have methods for simply finding an ancestor of a certain type without the need for a predicate. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,58 +3,31 @@ package groowt.util.di; | |||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import java.lang.annotation.Annotation; | import java.lang.annotation.Annotation; | ||||||
| import java.util.*; | import java.util.ArrayList; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| import java.util.function.Function; | import java.util.function.Function; | ||||||
| import java.util.function.Predicate; | import java.util.function.Predicate; | ||||||
| 
 | 
 | ||||||
| public class DefaultRegistry implements Registry { | public class DefaultRegistry implements Registry { | ||||||
| 
 | 
 | ||||||
|     protected static class BindingContainer { |     protected record ClassKeyBinding<T>(Class<T> key, Binding<T> binding) {} | ||||||
| 
 | 
 | ||||||
|         private final Map<Class<?>, Binding<?>> bindings = new HashMap<>(); |     protected final Collection<ClassKeyBinding<?>> classBindings = new ArrayList<>(); | ||||||
| 
 |  | ||||||
|         @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<>(); |     protected final Collection<RegistryExtension> extensions = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void removeBinding(Class<?> key) { |     public void removeBinding(Class<?> key) { | ||||||
|         this.bindingContainer.remove(key); |         this.classBindings.removeIf(classKeyBinding -> classKeyBinding.key().equals(key)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|     @Override |     @Override | ||||||
|     public <T> void removeBindingIf(Class<T> key, Predicate<Binding<T>> filter) { |     public <T> void removeBindingIf(Class<T> key, Predicate<Binding<T>> filter) { | ||||||
|         this.bindingContainer.removeIf(key, filter); |         this.classBindings.removeIf(classKeyBinding -> | ||||||
|  |                 classKeyBinding.key().equals(key) && filter.test((Binding<T>) classKeyBinding.binding()) | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private <E extends RegistryExtension> List<E> getAllRegistryExtensions(Class<E> extensionType) { |     private <E extends RegistryExtension> List<E> getAllRegistryExtensions(Class<E> extensionType) { | ||||||
| @ -144,12 +117,18 @@ public class DefaultRegistry implements Registry { | |||||||
|     public <T> void bind(Class<T> key, Consumer<? super BindingConfigurator<T>> configure) { |     public <T> void bind(Class<T> key, Consumer<? super BindingConfigurator<T>> configure) { | ||||||
|         final var configurator = new SimpleBindingConfigurator<>(key); |         final var configurator = new SimpleBindingConfigurator<>(key); | ||||||
|         configure.accept(configurator); |         configure.accept(configurator); | ||||||
|         this.bindingContainer.put(key, configurator.getBinding()); |         this.classBindings.add(new ClassKeyBinding<>(key, configurator.getBinding())); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|     @Override |     @Override | ||||||
|     public <T> @Nullable Binding<T> getBinding(Class<T> key) { |     public @Nullable <T> Binding<T> getBinding(Class<T> key) { | ||||||
|         return this.bindingContainer.get(key); |         for (final var classKeyBinding : this.classBindings) { | ||||||
|  |             if (key.isAssignableFrom(classKeyBinding.key())) { | ||||||
|  |                 return (Binding<T>) classKeyBinding.binding(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private KeyBinder<?> findKeyBinder(Class<?> keyClass) { |     private KeyBinder<?> findKeyBinder(Class<?> keyClass) { | ||||||
| @ -210,7 +189,7 @@ public class DefaultRegistry implements Registry { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void clearAllBindings() { |     public void clearAllBindings() { | ||||||
|         this.bindingContainer.clear(); |         this.classBindings.clear(); | ||||||
|         for (final var extension : this.extensions) { |         for (final var extension : this.extensions) { | ||||||
|             if (extension instanceof KeyBinder<?> keyBinder) { |             if (extension instanceof KeyBinder<?> keyBinder) { | ||||||
|                 keyBinder.clearAllBindings(); |                 keyBinder.clearAllBindings(); | ||||||
|  | |||||||
| @ -1,9 +1,8 @@ | |||||||
| package groowt.util.di; | package groowt.util.di; | ||||||
| 
 | 
 | ||||||
| import jakarta.inject.Provider; |  | ||||||
| import jakarta.inject.Singleton; | import jakarta.inject.Singleton; | ||||||
| 
 | 
 | ||||||
| import static groowt.util.di.BindingUtil.toLazySingleton; | import static groowt.util.di.BindingUtil.toSingleton; | ||||||
| 
 | 
 | ||||||
| public final class SingletonScopeHandler implements ScopeHandler<Singleton> { | public final class SingletonScopeHandler implements ScopeHandler<Singleton> { | ||||||
| 
 | 
 | ||||||
| @ -20,22 +19,12 @@ public final class SingletonScopeHandler implements ScopeHandler<Singleton> { | |||||||
|             RegistryObjectFactory objectFactory |             RegistryObjectFactory objectFactory | ||||||
|     ) { |     ) { | ||||||
|         final Binding<T> potentialBinding = this.owner.getBinding(dependencyClass); |         final Binding<T> potentialBinding = this.owner.getBinding(dependencyClass); | ||||||
|         return switch (potentialBinding) { |         if (potentialBinding != null) { | ||||||
|             case ClassBinding<T>(Class<T> from, Class<? extends T> to) -> { |             return potentialBinding; | ||||||
|                 this.owner.bind(from, toLazySingleton(() -> objectFactory.createInstance(to))); |         } else { | ||||||
|                 yield this.owner.getBinding(from); |             this.owner.bind(dependencyClass, toSingleton(objectFactory.createInstance(dependencyClass))); | ||||||
|  |             return this.owner.getBinding(dependencyClass); | ||||||
|         } |         } | ||||||
|             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 |     @Override | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ package groowt.util.di; | |||||||
| 
 | 
 | ||||||
| import jakarta.inject.Inject; | import jakarta.inject.Inject; | ||||||
| import jakarta.inject.Named; | import jakarta.inject.Named; | ||||||
| import jakarta.inject.Singleton; |  | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| 
 | 
 | ||||||
| import static groowt.util.di.BindingUtil.*; | import static groowt.util.di.BindingUtil.*; | ||||||
| @ -251,25 +250,4 @@ public class DefaultRegistryObjectFactoryTests { | |||||||
|         assertEquals("Given Greeting", g.greet()); |         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()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,8 +10,41 @@ public abstract class CachingComponentTemplateCompiler<U extends ComponentTempla | |||||||
| 
 | 
 | ||||||
|     private final Map<Class<? extends ViewComponent>, ComponentTemplateCompileResult> cache = new HashMap<>(); |     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 |     @Override | ||||||
|     public final ComponentTemplateCompileResult compile(U compileUnit) throws ComponentTemplateCompileException { |     public final ComponentTemplateCompileResult compile(U compileUnit) | ||||||
|  |             throws ComponentTemplateCompileException { | ||||||
|         if (this.cache.containsKey(compileUnit.getForClass())) { |         if (this.cache.containsKey(compileUnit.getForClass())) { | ||||||
|             return this.cache.get(compileUnit.getForClass()); |             return this.cache.get(compileUnit.getForClass()); | ||||||
|         } else { |         } else { | ||||||
|  | |||||||
| @ -4,9 +4,16 @@ import groowt.view.component.ViewComponent; | |||||||
| import groowt.view.component.compiler.source.ComponentTemplateSource; | import groowt.view.component.compiler.source.ComponentTemplateSource; | ||||||
| 
 | 
 | ||||||
| public interface ComponentTemplateCompileUnit { | public interface ComponentTemplateCompileUnit { | ||||||
|  | 
 | ||||||
|     String getDescriptiveName(); |     String getDescriptiveName(); | ||||||
|     Class<? extends ViewComponent> getForClass(); |     Class<? extends ViewComponent> getForClass(); | ||||||
|     String getDefaultPackageName(); |     String getDefaultPackageName(); | ||||||
|     ComponentTemplateSource getSource(); |     ComponentTemplateSource getSource(); | ||||||
|     ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException; |     ComponentTemplateCompileResult compile(ComponentTemplateCompilerConfiguration configuration) | ||||||
|  |             throws ComponentTemplateCompileException; | ||||||
|  | 
 | ||||||
|  |     default ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException { | ||||||
|  |         return this.compile(new DefaultComponentTemplateCompilerConfiguration()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,11 @@ | |||||||
|  | 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(); | ||||||
|  | } | ||||||
| @ -0,0 +1,48 @@ | |||||||
|  | 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); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -199,9 +199,7 @@ tasks.register('uberJar', Jar) { | |||||||
|     group 'groovyc' |     group 'groovyc' | ||||||
|     archiveBaseName = 'web-view-components-uber' |     archiveBaseName = 'web-view-components-uber' | ||||||
|     from sourceSets.main.output |     from sourceSets.main.output | ||||||
|     from sourceSets.main.runtimeClasspath |     from sourceSets.main.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) } | ||||||
|             .filter(File.&exists) |  | ||||||
|             .collect { it.isDirectory() ? it : zipTree(it) } |  | ||||||
|     duplicatesStrategy = DuplicatesStrategy.EXCLUDE |     duplicatesStrategy = DuplicatesStrategy.EXCLUDE | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,15 +4,14 @@ if [ "$1" == "--debug" ]; then | |||||||
|   shift |   shift | ||||||
|   gradle -q uberJar && \ |   gradle -q uberJar && \ | ||||||
|     java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 \ |     java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 \ | ||||||
|       -cp build/libs/web-view-components-uber-0.1.2.jar \ |       -cp build/libs/web-view-components-uber-0.1.0.jar \ | ||||||
|       org.codehaus.groovy.tools.FileSystemCompiler \ |       org.codehaus.groovy.tools.FileSystemCompiler \ | ||||||
|       --configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \ |       --configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \ | ||||||
|       -d groovyc-out \ |       -d groovyc-out \ | ||||||
|       "$@" |       "$@" | ||||||
| else | else | ||||||
|   gradle -q uberJar && \ |   gradle -q uberJar && \ | ||||||
|     java -cp build/libs/web-view-components-uber-0.1.2.jar \ |     groovyc -cp build/libs/web-view-components-uber-0.1.0.jar \ | ||||||
|       org.codehaus.groovy.tools.FileSystemCompiler \ |  | ||||||
|       --configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \ |       --configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \ | ||||||
|       -d groovyc-out \ |       -d groovyc-out \ | ||||||
|       "$@" |       "$@" | ||||||
|  | |||||||
| @ -1 +0,0 @@ | |||||||
| <Echo>Hello, World!</Echo> |  | ||||||
| @ -4,6 +4,7 @@ import groowt.view.component.compiler.*; | |||||||
| import groowt.view.component.web.WebViewComponentBugError; | import groowt.view.component.web.WebViewComponentBugError; | ||||||
| import groowt.view.component.web.ast.node.CompilationUnitNode; | import groowt.view.component.web.ast.node.CompilationUnitNode; | ||||||
| import groowt.view.component.web.transpile.DefaultGroovyTranspiler; | import groowt.view.component.web.transpile.DefaultGroovyTranspiler; | ||||||
|  | import org.antlr.v4.runtime.ParserRuleContext; | ||||||
| import org.codehaus.groovy.control.CompilationFailedException; | import org.codehaus.groovy.control.CompilationFailedException; | ||||||
| import org.codehaus.groovy.control.SourceUnit; | import org.codehaus.groovy.control.SourceUnit; | ||||||
| import org.codehaus.groovy.tools.GroovyClass; | import org.codehaus.groovy.tools.GroovyClass; | ||||||
| @ -15,12 +16,25 @@ public class DefaultWebViewComponentTemplateCompiler | |||||||
|         extends CachingComponentTemplateCompiler<WebViewComponentTemplateCompileUnit> |         extends CachingComponentTemplateCompiler<WebViewComponentTemplateCompileUnit> | ||||||
|         implements WebViewComponentTemplateCompiler { |         implements WebViewComponentTemplateCompiler { | ||||||
| 
 | 
 | ||||||
|     private final WebViewComponentTemplateCompilerConfiguration configuration; |     private final ComponentTemplateCompilerConfiguration configuration; | ||||||
| 
 | 
 | ||||||
|     public DefaultWebViewComponentTemplateCompiler(WebViewComponentTemplateCompilerConfiguration configuration) { |     public DefaultWebViewComponentTemplateCompiler(ComponentTemplateCompilerConfiguration configuration) { | ||||||
|         this.configuration = 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 |     @Override | ||||||
|     protected ComponentTemplateCompileResult doCompile(WebViewComponentTemplateCompileUnit compileUnit) |     protected ComponentTemplateCompileResult doCompile(WebViewComponentTemplateCompileUnit compileUnit) | ||||||
|             throws ComponentTemplateCompileException { |             throws ComponentTemplateCompileException { | ||||||
| @ -35,12 +49,22 @@ public class DefaultWebViewComponentTemplateCompiler | |||||||
|                 : "AnonymousWebViewComponent" + System.nanoTime(); |                 : "AnonymousWebViewComponent" + System.nanoTime(); | ||||||
|         final var templateClassSimpleName = ownerComponentName + "Template"; |         final var templateClassSimpleName = ownerComponentName + "Template"; | ||||||
| 
 | 
 | ||||||
|         final SourceUnit sourceUnit = transpiler.transpile(compileUnit, cuNode, templateClassSimpleName); |         final SourceUnit sourceUnit = transpiler.transpile( | ||||||
|  |                 this.configuration, | ||||||
|  |                 compileUnit, | ||||||
|  |                 cuNode, | ||||||
|  |                 templateClassSimpleName | ||||||
|  |         ); | ||||||
|         compileUnit.getGroovyCompilationUnit().addSource(sourceUnit); |         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 |         // compile groovy | ||||||
|         try { |         try { | ||||||
|             compileUnit.getGroovyCompilationUnit().compile(this.configuration.getCompilePhase().getPhaseNumber()); |             compileUnit.getGroovyCompilationUnit().compile(this.configuration.getToCompilePhase().getPhaseNumber()); | ||||||
|         } catch (CompilationFailedException compilationFailedException) { |         } catch (CompilationFailedException compilationFailedException) { | ||||||
|             throw new WebViewComponentTemplateCompileException( |             throw new WebViewComponentTemplateCompileException( | ||||||
|                     compileUnit, |                     compileUnit, | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| package groowt.view.component.web.compiler; | package groowt.view.component.web.compiler; | ||||||
| 
 | 
 | ||||||
|  | import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration; | ||||||
|  | 
 | ||||||
| public class DefaultWebViewComponentTemplateCompilerFactory implements WebViewComponentTemplateCompilerFactory { | public class DefaultWebViewComponentTemplateCompilerFactory implements WebViewComponentTemplateCompilerFactory { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public WebViewComponentTemplateCompiler create(WebViewComponentTemplateCompilerConfiguration configuration) { |     public WebViewComponentTemplateCompiler create(ComponentTemplateCompilerConfiguration configuration) { | ||||||
|         return new DefaultWebViewComponentTemplateCompiler(configuration); |         return new DefaultWebViewComponentTemplateCompiler(configuration); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package groowt.view.component.web.groovyc; | package groowt.view.component.web.groovyc; | ||||||
| 
 | 
 | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileException; | import groowt.view.component.compiler.ComponentTemplateCompileException; | ||||||
|  | import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration; | ||||||
| import groowt.view.component.compiler.source.ComponentTemplateSource; | import groowt.view.component.compiler.source.ComponentTemplateSource; | ||||||
| import groowt.view.component.web.WebViewComponentBugError; | import groowt.view.component.web.WebViewComponentBugError; | ||||||
| import groowt.view.component.web.ast.node.CompilationUnitNode; | import groowt.view.component.web.ast.node.CompilationUnitNode; | ||||||
| @ -79,12 +80,13 @@ public class DelegatingWebViewComponentTemplateParserPlugin implements ParserPlu | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             final var groovyTranspiler = new DefaultGroovyTranspiler(); |             final var groovyTranspiler = new DefaultGroovyTranspiler(); | ||||||
|             final String templateClassName = sourceUnitFileName.substring(0, sourceUnitFileName.length() - 4); |             final String teplateClassSimpleName = sourceUnitFileName.substring(0, sourceUnitFileName.length() - 4); | ||||||
|             try { |             try { | ||||||
|                 final SourceUnit transpiledSourceUnit = groovyTranspiler.transpile( |                 final SourceUnit transpiledSourceUnit = groovyTranspiler.transpile( | ||||||
|  |                         new DefaultComponentTemplateCompilerConfiguration(), | ||||||
|                         compileUnit, |                         compileUnit, | ||||||
|                         cuNode, |                         cuNode, | ||||||
|                         templateClassName |                         teplateClassSimpleName | ||||||
|                 ); |                 ); | ||||||
|                 return transpiledSourceUnit.getAST(); |                 return transpiledSourceUnit.getAST(); | ||||||
|             } catch (ComponentTemplateCompileException e) { |             } catch (ComponentTemplateCompileException e) { | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import groowt.view.component.web.WebViewComponentBugError; | |||||||
| import groowt.view.component.web.ast.node.*; | import groowt.view.component.web.ast.node.*; | ||||||
| import groowt.view.component.web.transpile.groovy.GroovyUtil; | import groowt.view.component.web.transpile.groovy.GroovyUtil; | ||||||
| import groowt.view.component.web.transpile.groovy.GroovyUtil.ConvertResult; | 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 groowt.view.component.web.util.SourcePosition; | ||||||
| import org.codehaus.groovy.ast.*; | import org.codehaus.groovy.ast.*; | ||||||
| import org.codehaus.groovy.ast.expr.*; | import org.codehaus.groovy.ast.expr.*; | ||||||
| @ -14,6 +15,7 @@ import org.jetbrains.annotations.Nullable; | |||||||
| 
 | 
 | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.regex.Pattern; | ||||||
| 
 | 
 | ||||||
| import static groowt.view.component.web.transpile.TranspilerUtil.*; | import static groowt.view.component.web.transpile.TranspilerUtil.*; | ||||||
| 
 | 
 | ||||||
| @ -23,9 +25,13 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { | |||||||
|     private static final ClassNode COMPONENT_RESOLVE_EXCEPTION_TYPE = ClassHelper.make(ComponentResolveException.class); |     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 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 LeftShiftFactory leftShiftFactory; | ||||||
|     private ValueNodeTranspiler valueNodeTranspiler; |     private ValueNodeTranspiler valueNodeTranspiler; | ||||||
|     private BodyTranspiler bodyTranspiler; |     private BodyTranspiler bodyTranspiler; | ||||||
|  |     private ComponentClassNodeResolver componentClassNodeResolver; | ||||||
| 
 | 
 | ||||||
|     public void setLeftShiftFactory(LeftShiftFactory leftShiftFactory) { |     public void setLeftShiftFactory(LeftShiftFactory leftShiftFactory) { | ||||||
|         this.leftShiftFactory = leftShiftFactory; |         this.leftShiftFactory = leftShiftFactory; | ||||||
| @ -39,6 +45,10 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { | |||||||
|         this.bodyTranspiler = bodyTranspiler; |         this.bodyTranspiler = bodyTranspiler; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) { | ||||||
|  |         this.componentClassNodeResolver = componentClassNodeResolver; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* UTIL */ |     /* UTIL */ | ||||||
| 
 | 
 | ||||||
|     protected String getComponentName(int componentNumber) { |     protected String getComponentName(int componentNumber) { | ||||||
| @ -64,14 +74,49 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { | |||||||
| 
 | 
 | ||||||
|     /* RESOLVE */ |     /* RESOLVE */ | ||||||
| 
 | 
 | ||||||
|     protected List<Expression> getArgsAsList(TypedComponentNode componentNode) { |     protected List<Expression> getArgsAsList( | ||||||
|  |             TypedComponentNode componentNode, | ||||||
|  |             TranspilerState state | ||||||
|  |     ) { | ||||||
|         return switch (componentNode.getArgs().getType()) { |         return switch (componentNode.getArgs().getType()) { | ||||||
|             case ClassComponentTypeNode classComponentTypeNode -> { |             case ClassComponentTypeNode classComponentTypeNode -> { | ||||||
|                 final String identifier = classComponentTypeNode.getIdentifier(); |                 final String identifier = classComponentTypeNode.getIdentifier(); | ||||||
|                 final ConstantExpression alias = getStringLiteral(identifier); |                 final ConstantExpression alias = getStringLiteral(identifier); | ||||||
|  |                 final var matcher = isFqn.matcher(identifier); | ||||||
|  |                 if (matcher.matches()) { | ||||||
|                     final ClassNode classNode = ClassHelper.make(identifier); |                     final ClassNode classNode = ClassHelper.make(identifier); | ||||||
|                 final var classExpression = new ClassExpression(classNode); |                     final ClassExpression classExpression = new ClassExpression(classNode); | ||||||
|                     yield List.of(alias, classExpression); |                     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 -> { |             case StringComponentTypeNode stringComponentTypeNode -> { | ||||||
|                 final String identifier = stringComponentTypeNode.getIdentifier(); |                 final String identifier = stringComponentTypeNode.getIdentifier(); | ||||||
| @ -82,8 +127,8 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // 'h1' | 'MyComponent', MyComponent(.class) |     // 'h1' | 'MyComponent', MyComponent(.class) | ||||||
|     protected ArgumentListExpression getResolveArgs(TypedComponentNode componentNode) { |     protected ArgumentListExpression getResolveArgs(TypedComponentNode componentNode, TranspilerState state) { | ||||||
|         final List<Expression> args = this.getArgsAsList(componentNode); |         final List<Expression> args = this.getArgsAsList(componentNode, state); | ||||||
|         final ArgumentListExpression argsListExpr = new ArgumentListExpression(); |         final ArgumentListExpression argsListExpr = new ArgumentListExpression(); | ||||||
|         args.forEach(argsListExpr::addExpression); |         args.forEach(argsListExpr::addExpression); | ||||||
|         return argsListExpr; |         return argsListExpr; | ||||||
| @ -97,7 +142,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { | |||||||
|         return new MethodCallExpression( |         return new MethodCallExpression( | ||||||
|                 new VariableExpression(state.getRenderContext()), |                 new VariableExpression(state.getRenderContext()), | ||||||
|                 "resolve", |                 "resolve", | ||||||
|                 this.getResolveArgs(componentNode) |                 this.getResolveArgs(componentNode, state) | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ package groowt.view.component.web.transpile; | |||||||
| 
 | 
 | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileException; | import groowt.view.component.compiler.ComponentTemplateCompileException; | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileUnit; | 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.BodyNode; | ||||||
| import groowt.view.component.web.ast.node.CompilationUnitNode; | import groowt.view.component.web.ast.node.CompilationUnitNode; | ||||||
| import groowt.view.component.web.ast.node.PreambleNode; | import groowt.view.component.web.ast.node.PreambleNode; | ||||||
| @ -9,6 +10,7 @@ import groowt.view.component.web.compiler.MultipleWebViewComponentCompileErrorsE | |||||||
| import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException; | import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException; | ||||||
| import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; | import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; | ||||||
| import groowt.view.component.web.transpile.groovy.GroovyUtil; | 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.*; | ||||||
| import org.codehaus.groovy.ast.expr.*; | import org.codehaus.groovy.ast.expr.*; | ||||||
| import org.codehaus.groovy.ast.stmt.BlockStatement; | import org.codehaus.groovy.ast.stmt.BlockStatement; | ||||||
| @ -29,13 +31,25 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { | |||||||
| 
 | 
 | ||||||
|     private static final Logger logger = LoggerFactory.getLogger(DefaultGroovyTranspiler.class); |     private static final Logger logger = LoggerFactory.getLogger(DefaultGroovyTranspiler.class); | ||||||
| 
 | 
 | ||||||
|     protected TranspilerConfiguration getConfiguration() { |     protected TranspilerConfiguration getConfiguration( | ||||||
|         return SimpleTranspilerConfiguration.withDefaults(); |             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 WebViewComponentModuleNode initModuleNode( |     protected WebViewComponentModuleNode initModuleNode( | ||||||
|             ComponentTemplateCompileUnit compileUnit, |             ComponentTemplateCompileUnit compileUnit, | ||||||
|             WebViewComponentSourceUnit sourceUnit |             WebViewComponentSourceUnit sourceUnit, | ||||||
|  |             TranspilerConfiguration configuration | ||||||
|     ) { |     ) { | ||||||
|         final var moduleNode = new WebViewComponentModuleNode(sourceUnit); |         final var moduleNode = new WebViewComponentModuleNode(sourceUnit); | ||||||
|         sourceUnit.setModuleNode(moduleNode); |         sourceUnit.setModuleNode(moduleNode); | ||||||
| @ -45,16 +59,22 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { | |||||||
|             moduleNode.setPackageName(defaultPackageName); |             moduleNode.setPackageName(defaultPackageName); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         this.addAutomaticImports(moduleNode, configuration); | ||||||
|         return moduleNode; |         return moduleNode; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected ClassNode initMainClassNode(ComponentTemplateCompileUnit compileUnit, String templateClassName) { |     protected ClassNode initMainClassNode( | ||||||
|  |             ComponentTemplateCompileUnit compileUnit, | ||||||
|  |             String templateClassName, | ||||||
|  |             WebViewComponentModuleNode moduleNode | ||||||
|  |     ) { | ||||||
|         final ClassNode mainClassNode = new ClassNode( |         final ClassNode mainClassNode = new ClassNode( | ||||||
|                 compileUnit.getDefaultPackageName() + templateClassName, |                 compileUnit.getDefaultPackageName() + templateClassName, | ||||||
|                 ACC_PUBLIC, |                 ACC_PUBLIC, | ||||||
|                 ClassHelper.OBJECT_TYPE |                 ClassHelper.OBJECT_TYPE | ||||||
|         ); |         ); | ||||||
|         mainClassNode.addInterface(TranspilerUtil.COMPONENT_TEMPLATE); |         mainClassNode.addInterface(TranspilerUtil.COMPONENT_TEMPLATE); | ||||||
|  |         moduleNode.addClass(mainClassNode); | ||||||
|         return mainClassNode; |         return mainClassNode; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -196,32 +216,40 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public WebViewComponentSourceUnit transpile( |     public WebViewComponentSourceUnit transpile( | ||||||
|  |             ComponentTemplateCompilerConfiguration compilerConfiguration, | ||||||
|             WebViewComponentTemplateCompileUnit compileUnit, |             WebViewComponentTemplateCompileUnit compileUnit, | ||||||
|             CompilationUnitNode compilationUnitNode, |             CompilationUnitNode compilationUnitNode, | ||||||
|             String templateClassSimpleName |             String templateClassSimpleName | ||||||
|     ) throws ComponentTemplateCompileException { |     ) throws ComponentTemplateCompileException { | ||||||
|         // transpilerConfiguration, and positionSetter |         // resolver, transpilerConfiguration, and positionSetter | ||||||
|         final var transpilerConfiguration = this.getConfiguration(); |         final ClassLoaderComponentClassNodeResolver resolver = new ClassLoaderComponentClassNodeResolver( | ||||||
|  |                 compileUnit, | ||||||
|  |                 compilerConfiguration.getGroovyClassLoader() | ||||||
|  |         ); | ||||||
|  |         final var transpilerConfiguration = this.getConfiguration(resolver); | ||||||
|         final PositionSetter positionSetter = transpilerConfiguration.getPositionSetter(); |         final PositionSetter positionSetter = transpilerConfiguration.getPositionSetter(); | ||||||
| 
 | 
 | ||||||
|         // prepare sourceUnit |         // prepare sourceUnit | ||||||
|         final CompilerConfiguration groovyCompilerConfiguration = compileUnit.getGroovyCompilationUnit() |         final CompilerConfiguration groovyCompilerConfiguration = | ||||||
|                 .getConfiguration(); |                 compilerConfiguration.getGroovyCompilerConfiguration(); | ||||||
|         final WebViewComponentSourceUnit sourceUnit = new WebViewComponentSourceUnit( |         final WebViewComponentSourceUnit sourceUnit = new WebViewComponentSourceUnit( | ||||||
|                 compileUnit.getDescriptiveName(), |                 compileUnit.getDescriptiveName(), | ||||||
|                 compileUnit.getGroovyReaderSource(), |                 compileUnit.getGroovyReaderSource(), | ||||||
|                 groovyCompilerConfiguration, |                 groovyCompilerConfiguration, | ||||||
|                 compileUnit.getGroovyCompilationUnit().getClassLoader(), |                 compilerConfiguration.getGroovyClassLoader(), | ||||||
|                 new ErrorCollector(groovyCompilerConfiguration) |                 new ErrorCollector(groovyCompilerConfiguration) | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         // prepare moduleNode |         // prepare moduleNode | ||||||
|         final WebViewComponentModuleNode moduleNode = this.initModuleNode( |         final WebViewComponentModuleNode moduleNode = this.initModuleNode( | ||||||
|                 compileUnit, sourceUnit |                 compileUnit, sourceUnit, transpilerConfiguration | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|  |         // set resolver's moduleNode | ||||||
|  |         resolver.setModuleNode(moduleNode); | ||||||
|  | 
 | ||||||
|         // prepare mainClassNode |         // prepare mainClassNode | ||||||
|         final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName); |         final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName, moduleNode); | ||||||
| 
 | 
 | ||||||
|         // handle preamble |         // handle preamble | ||||||
|         final PreambleNode preambleNode = compilationUnitNode.getPreambleNode(); |         final PreambleNode preambleNode = compilationUnitNode.getPreambleNode(); | ||||||
| @ -229,9 +257,6 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { | |||||||
|             this.handlePreamble(templateClassSimpleName, preambleNode, mainClassNode, moduleNode, positionSetter); |             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 |         // getRenderer method and render closure | ||||||
|         // first, getRenderer params |         // first, getRenderer params | ||||||
|         final Parameter componentContextParam = new Parameter(COMPONENT_CONTEXT_TYPE, COMPONENT_CONTEXT_NAME); |         final Parameter componentContextParam = new Parameter(COMPONENT_CONTEXT_TYPE, COMPONENT_CONTEXT_NAME); | ||||||
|  | |||||||
| @ -1,12 +1,14 @@ | |||||||
| package groowt.view.component.web.transpile; | package groowt.view.component.web.transpile; | ||||||
| 
 | 
 | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileException; | 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.ast.node.CompilationUnitNode; | ||||||
| import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; | import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; | ||||||
| 
 | 
 | ||||||
| public interface GroovyTranspiler { | public interface GroovyTranspiler { | ||||||
| 
 | 
 | ||||||
|     WebViewComponentSourceUnit transpile( |     WebViewComponentSourceUnit transpile( | ||||||
|  |             ComponentTemplateCompilerConfiguration compilerConfiguration, | ||||||
|             WebViewComponentTemplateCompileUnit compileUnit, |             WebViewComponentTemplateCompileUnit compileUnit, | ||||||
|             CompilationUnitNode compilationUnitNode, |             CompilationUnitNode compilationUnitNode, | ||||||
|             String templateClassSimpleName |             String templateClassSimpleName | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package groowt.view.component.web.transpile; | package groowt.view.component.web.transpile; | ||||||
| 
 | 
 | ||||||
| import groovy.lang.Tuple3; | import groovy.lang.Tuple3; | ||||||
|  | import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver; | ||||||
| import org.codehaus.groovy.ast.ClassNode; | import org.codehaus.groovy.ast.ClassNode; | ||||||
| 
 | 
 | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| @ -11,8 +12,9 @@ import static groowt.view.component.web.transpile.TranspilerUtil.*; | |||||||
| 
 | 
 | ||||||
| public class SimpleTranspilerConfiguration implements TranspilerConfiguration { | public class SimpleTranspilerConfiguration implements TranspilerConfiguration { | ||||||
| 
 | 
 | ||||||
|     public static TranspilerConfiguration withDefaults() { |     public static TranspilerConfiguration withDefaults(ComponentClassNodeResolver componentClassNodeResolver) { | ||||||
|         final var c = new SimpleTranspilerConfiguration(); |         final var c = new SimpleTranspilerConfiguration(); | ||||||
|  |         c.setComponentClassNodeResolver(componentClassNodeResolver); | ||||||
| 
 | 
 | ||||||
|         final var ct = new DefaultComponentTranspiler(); |         final var ct = new DefaultComponentTranspiler(); | ||||||
|         final PositionSetter ps = new SimplePositionSetter(); |         final PositionSetter ps = new SimplePositionSetter(); | ||||||
| @ -25,6 +27,7 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration { | |||||||
|         ct.setLeftShiftFactory(lsf); |         ct.setLeftShiftFactory(lsf); | ||||||
|         ct.setBodyTranspiler(bt); |         ct.setBodyTranspiler(bt); | ||||||
|         ct.setValueNodeTranspiler(vnt); |         ct.setValueNodeTranspiler(vnt); | ||||||
|  |         ct.setComponentClassNodeResolver(componentClassNodeResolver); | ||||||
| 
 | 
 | ||||||
|         c.setComponentTranspiler(ct); |         c.setComponentTranspiler(ct); | ||||||
|         c.setPositionSetter(ps); |         c.setPositionSetter(ps); | ||||||
| @ -37,6 +40,7 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration { | |||||||
|         return c; |         return c; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private ComponentClassNodeResolver componentClassNodeResolver; | ||||||
|     private ComponentTranspiler componentTranspiler; |     private ComponentTranspiler componentTranspiler; | ||||||
|     private PositionSetter positionSetter; |     private PositionSetter positionSetter; | ||||||
|     private LeftShiftFactory leftShiftFactory; |     private LeftShiftFactory leftShiftFactory; | ||||||
| @ -45,6 +49,14 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration { | |||||||
|     private BodyTranspiler bodyTranspiler; |     private BodyTranspiler bodyTranspiler; | ||||||
|     private ValueNodeTranspiler valueNodeTranspiler; |     private ValueNodeTranspiler valueNodeTranspiler; | ||||||
| 
 | 
 | ||||||
|  |     public ComponentClassNodeResolver getComponentClassNodeResolver() { | ||||||
|  |         return Objects.requireNonNull(this.componentClassNodeResolver); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) { | ||||||
|  |         this.componentClassNodeResolver = componentClassNodeResolver; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public ComponentTranspiler getComponentTranspiler() { |     public ComponentTranspiler getComponentTranspiler() { | ||||||
|         return Objects.requireNonNull(this.componentTranspiler); |         return Objects.requireNonNull(this.componentTranspiler); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -0,0 +1,60 @@ | |||||||
|  | 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 | ||||||
|  |         )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,53 @@ | |||||||
|  | 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; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,42 @@ | |||||||
|  | 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); | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,84 @@ | |||||||
|  | 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." | ||||||
|  |                 )); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,31 @@ | |||||||
|  | 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,16 +1,5 @@ | |||||||
| package groowt.view.component.web.groovyc | package groowt.view.component.web.groovyc | ||||||
| 
 | 
 | ||||||
| import org.codehaus.groovy.control.CompilerConfiguration | 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,6 +3,7 @@ package groowt.view.component.web.transpiler; | |||||||
| import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; | import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; | ||||||
| import groowt.view.component.web.transpile.SimpleTranspilerConfiguration; | import groowt.view.component.web.transpile.SimpleTranspilerConfiguration; | ||||||
| import groowt.view.component.web.transpile.TranspilerConfiguration; | import groowt.view.component.web.transpile.TranspilerConfiguration; | ||||||
|  | import groowt.view.component.web.transpile.resolve.CachingComponentClassNodeResolver; | ||||||
| import org.codehaus.groovy.ast.ModuleNode; | import org.codehaus.groovy.ast.ModuleNode; | ||||||
| 
 | 
 | ||||||
| public class DefaultBodyTranspilerTests extends BodyTranspilerTests { | public class DefaultBodyTranspilerTests extends BodyTranspilerTests { | ||||||
| @ -12,7 +13,7 @@ public class DefaultBodyTranspilerTests extends BodyTranspilerTests { | |||||||
|             WebViewComponentTemplateCompileUnit compileUnit, |             WebViewComponentTemplateCompileUnit compileUnit, | ||||||
|             ModuleNode moduleNode |             ModuleNode moduleNode | ||||||
|     ) { |     ) { | ||||||
|         return SimpleTranspilerConfiguration.withDefaults(); |         return SimpleTranspilerConfiguration.withDefaults(new CachingComponentClassNodeResolver(compileUnit)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,25 @@ | |||||||
|  | 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,6 +2,7 @@ package groowt.view.component.web.transpiler; | |||||||
| 
 | 
 | ||||||
| import groovy.lang.Tuple2; | import groovy.lang.Tuple2; | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileException; | import groowt.view.component.compiler.ComponentTemplateCompileException; | ||||||
|  | import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration; | ||||||
| import groowt.view.component.compiler.source.StringSource; | import groowt.view.component.compiler.source.StringSource; | ||||||
| import groowt.view.component.web.BaseWebViewComponent; | import groowt.view.component.web.BaseWebViewComponent; | ||||||
| import groowt.view.component.web.antlr.ParserUtil; | import groowt.view.component.web.antlr.ParserUtil; | ||||||
| @ -54,6 +55,7 @@ public abstract class GroovyTranspilerTests { | |||||||
|         final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext()); |         final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext()); | ||||||
|         try { |         try { | ||||||
|             this.transpiler.transpile( |             this.transpiler.transpile( | ||||||
|  |                     new DefaultComponentTemplateCompilerConfiguration(), | ||||||
|                     new DefaultWebViewComponentTemplateCompileUnit( |                     new DefaultWebViewComponentTemplateCompileUnit( | ||||||
|                             "<anonymous string source>", |                             "<anonymous string source>", | ||||||
|                             AnonymousWebViewComponent.class, |                             AnonymousWebViewComponent.class, | ||||||
|  | |||||||
| @ -9,7 +9,6 @@ import org.apache.logging.log4j.core.LoggerContext; | |||||||
| import org.codehaus.groovy.control.CompilationFailedException; | import org.codehaus.groovy.control.CompilationFailedException; | ||||||
| import org.codehaus.groovy.control.CompilationUnit; | import org.codehaus.groovy.control.CompilationUnit; | ||||||
| import org.codehaus.groovy.control.CompilerConfiguration; | import org.codehaus.groovy.control.CompilerConfiguration; | ||||||
| import org.codehaus.groovy.control.customizers.ImportCustomizer; |  | ||||||
| import picocli.CommandLine; | import picocli.CommandLine; | ||||||
| import picocli.CommandLine.Command; | import picocli.CommandLine.Command; | ||||||
| 
 | 
 | ||||||
| @ -72,15 +71,6 @@ public final class GroovyWvcCompiler implements Callable<Integer> { | |||||||
| 
 | 
 | ||||||
|     public Integer doCompile() { |     public Integer doCompile() { | ||||||
|         final CompilerConfiguration configuration = new CompilerConfiguration(); |         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()); |         configuration.setPluginFactory(new WebViewComponentParserPluginFactory()); | ||||||
|         final CompilationUnit compilationUnit = new CompilationUnit(configuration); |         final CompilationUnit compilationUnit = new CompilationUnit(configuration); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,14 +4,13 @@ import groowt.view.component.ViewComponent; | |||||||
| import groowt.view.component.compiler.AbstractComponentTemplateCompileUnit; | import groowt.view.component.compiler.AbstractComponentTemplateCompileUnit; | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileException; | import groowt.view.component.compiler.ComponentTemplateCompileException; | ||||||
| import groowt.view.component.compiler.ComponentTemplateCompileResult; | 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.ComponentTemplateSource; | ||||||
| import groowt.view.component.compiler.source.FileSource; | import groowt.view.component.compiler.source.FileSource; | ||||||
| import groowt.view.component.compiler.source.URISource; | import groowt.view.component.compiler.source.URISource; | ||||||
| import groowt.view.component.compiler.source.URLSource; | import groowt.view.component.compiler.source.URLSource; | ||||||
| import org.codehaus.groovy.control.CompilationUnit; | import org.codehaus.groovy.control.CompilationUnit; | ||||||
| import org.codehaus.groovy.control.CompilerConfiguration; |  | ||||||
| import org.codehaus.groovy.control.Janitor; | import org.codehaus.groovy.control.Janitor; | ||||||
| import org.codehaus.groovy.control.customizers.ImportCustomizer; |  | ||||||
| import org.codehaus.groovy.control.io.ReaderSource; | import org.codehaus.groovy.control.io.ReaderSource; | ||||||
| import org.jetbrains.annotations.Nullable; | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| @ -21,20 +20,8 @@ import java.net.URI; | |||||||
| public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponentTemplateCompileUnit | public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponentTemplateCompileUnit | ||||||
|         implements ReaderSource, WebViewComponentTemplateCompileUnit { |         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 String defaultPackageName; | ||||||
|     private final CompilationUnit groovyCompilationUnit; |     private final CompilationUnit groovyCompilationUnit = new CompilationUnit(); | ||||||
| 
 | 
 | ||||||
|     public DefaultWebViewComponentTemplateCompileUnit( |     public DefaultWebViewComponentTemplateCompileUnit( | ||||||
|             String descriptiveName, |             String descriptiveName, | ||||||
| @ -48,7 +35,6 @@ public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponen | |||||||
|         } else { |         } else { | ||||||
|             this.defaultPackageName = defaultPackageName; |             this.defaultPackageName = defaultPackageName; | ||||||
|         } |         } | ||||||
|         this.groovyCompilationUnit = getCompilationUnit(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
| @ -67,8 +53,9 @@ public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponen | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException { |     public ComponentTemplateCompileResult compile(ComponentTemplateCompilerConfiguration configuration) | ||||||
|         final WebViewComponentTemplateCompiler compiler = WebViewComponentTemplateCompiler.get(); |             throws ComponentTemplateCompileException { | ||||||
|  |         final WebViewComponentTemplateCompiler compiler = WebViewComponentTemplateCompiler.get(configuration); | ||||||
|         return compiler.compile(this); |         return compiler.compile(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,10 +9,10 @@ public interface WebViewComponentTemplateCompiler | |||||||
|         extends ComponentTemplateCompiler<WebViewComponentTemplateCompileUnit> { |         extends ComponentTemplateCompiler<WebViewComponentTemplateCompileUnit> { | ||||||
| 
 | 
 | ||||||
|     static WebViewComponentTemplateCompiler get() { |     static WebViewComponentTemplateCompiler get() { | ||||||
|         return get(new WebViewComponentTemplateCompilerConfiguration()); |         return get(new DefaultComponentTemplateCompilerConfiguration()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static WebViewComponentTemplateCompiler get(WebViewComponentTemplateCompilerConfiguration configuration) { |     static WebViewComponentTemplateCompiler get(ComponentTemplateCompilerConfiguration configuration) { | ||||||
|         final ServiceLoader<WebViewComponentTemplateCompilerFactory> factoryServiceLoader = |         final ServiceLoader<WebViewComponentTemplateCompilerFactory> factoryServiceLoader = | ||||||
|                 ServiceLoader.load(WebViewComponentTemplateCompilerFactory.class); |                 ServiceLoader.load(WebViewComponentTemplateCompilerFactory.class); | ||||||
|         final var factory = factoryServiceLoader.findFirst() |         final var factory = factoryServiceLoader.findFirst() | ||||||
|  | |||||||
| @ -1,17 +0,0 @@ | |||||||
| 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,5 +1,7 @@ | |||||||
| package groowt.view.component.web.compiler; | package groowt.view.component.web.compiler; | ||||||
| 
 | 
 | ||||||
|  | import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration; | ||||||
|  | 
 | ||||||
| public interface WebViewComponentTemplateCompilerFactory { | public interface WebViewComponentTemplateCompilerFactory { | ||||||
|     WebViewComponentTemplateCompiler create(WebViewComponentTemplateCompilerConfiguration configuration); |     WebViewComponentTemplateCompiler create(ComponentTemplateCompilerConfiguration configuration); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user