Skip to content
This repository has been archived by the owner on Oct 12, 2021. It is now read-only.

Commit

Permalink
Add support for CssImport attributes (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
johndevs committed Jan 12, 2020
1 parent 12dd505 commit b317fd4
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ class VaadinFlowPluginAction extends PluginAction {
project.with {
tasks[PROCESS_RESOURCES].with {
dependsOn(VersionCheckTask.NAME)
dependsOn(WrapCssTask.NAME)
dependsOn(ConvertGroovyTemplatesToHTML.NAME)
}

Expand Down
81 changes: 69 additions & 12 deletions src/main/groovy/com/devsoap/vaadinflow/tasks/WrapCssTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package com.devsoap.vaadinflow.tasks

import com.devsoap.vaadinflow.actions.JavaPluginAction
import com.devsoap.vaadinflow.extensions.VaadinFlowPluginExtension
import com.devsoap.vaadinflow.util.ClassIntrospectionUtils
import groovy.util.logging.Log
import io.github.classgraph.ScanResult
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileTree
import org.gradle.api.tasks.CacheableTask
Expand Down Expand Up @@ -48,9 +50,10 @@ class WrapCssTask extends DefaultTask {
static final String STYLES_TARGET_PATH = 'webapp-gen/frontend/styles'
static final String CSS_REGEXP = '**/*.css'

private static final String CSS = '.css'
private static final String CSS = CSS_EXTENSION
private static final String FRONTEND = 'frontend'
private static final String STYLES = 'styles'
public static final String CSS_EXTENSION = '.css'

@Optional
@InputDirectory
Expand Down Expand Up @@ -94,6 +97,7 @@ class WrapCssTask extends DefaultTask {
WrapCssTask() {
group = 'vaadin'
description = 'Wraps CSS files in HTML/JS wrappers'
dependsOn('classes')
}

@TaskAction
Expand All @@ -117,6 +121,7 @@ class WrapCssTask extends DefaultTask {
}
}

@Deprecated
private void convertToHtml(FileTree tree) {
tree.each {
LOGGER.info("Wrapping $it in HTML wrapper")
Expand All @@ -134,23 +139,75 @@ class WrapCssTask extends DefaultTask {
}

private void convertToJs(FileTree tree) {

VaadinFlowPluginExtension vaadin = project.extensions.getByType(VaadinFlowPluginExtension)
ScanResult scan = ClassIntrospectionUtils.getAnnotationScan(project)
Map<String,Map<String,String>> cssImports = ClassIntrospectionUtils.findCssImports(vaadin, scan)
.collectEntries { [new File(cssSourceDir.call(), it.key).canonicalPath, it.value] }

tree.each {
LOGGER.info("Wrapping $it in JS wrapper")
String content =
"""
// This is a autogenerated Javascript file for ${it.name}. Do not edit this file, it will be overwritten.
import '@polymer/polymer/lib/elements/custom-style.js';
const \$_documentContainer = document.createElement('template');
\$_documentContainer.innerHTML = `<style>
$it.text
</style>`;
document.head.appendChild(\$_documentContainer.content);
"""
Map<String,String> values = cssImports[it.canonicalPath]
String content = writeAutogeneratedComment(it.name)
if (!values) {
LOGGER.warning("Could not match file ${it.canonicalPath} to any @CssImport annotation.")
content += writeNoValueTemplate(it.name, it.text)
} else if (values?.target || values?.id) {
content += writeTargetOrIdValueTemplate(it.name, it.text, values)
} else {
content += writeAllValuesTemplate(it.name, it.text, values)
}
content += writeDocumentAppend()

File js = new File(targetPath.call(), "${ cssSourceDir.call().relativePath(it) - CSS }.js" )
js.parentFile.mkdirs()
js.text = content
}
}

private static String writeNoValueTemplate(String name, String css) {
"""
const \$_documentContainer = document.createElement('custom-style');
\$_documentContainer.setAttribute("id", "wrapped-${name - CSS_EXTENSION}");
\$_documentContainer.innerHTML = `<style>
$css
</style>`;
""".stripIndent()
}

private static String writeTargetOrIdValueTemplate(String name, String css, Map<String,String> values) {
"""
const \$_documentContainer = document.createElement('dom-module');
${values.id ? "\$_documentContainer.setAttribute(\"id\",\"${values.id}\");" : '' }
${values.target ? "\$_documentContainer.setAttribute(\"theme-for\",\"${values.target}\");" : '' }
\$_documentContainer.innerHTML = `<template id="wrapped-${name - CSS_EXTENSION}">
<style ${values.include ? "include=\"${values.include}\"" : ''}>
$css
</style>
</template>`;
""".stripIndent()
}

private static String writeAllValuesTemplate(String name, String css, Map<String,String> values) {
"""
const \$_documentContainer = document.createElement('custom-style');
\$_documentContainer.setAttribute("id", "wrapped-${name - CSS_EXTENSION}");
\$_documentContainer.innerHTML = `
<style ${values.include ? "include=\"${ values.include }\"" : ''}>
$css
</style>`;
""".stripIndent()
}

private static String writeAutogeneratedComment(String name) {
"""
// This is a autogenerated Javascript file for ${name}. Do not edit this file, it will be overwritten.
""".stripIndent()
}

private static String writeDocumentAppend() {
"""
document.head.appendChild(\$_documentContainer);
""".stripIndent()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
package com.devsoap.vaadinflow.util

import com.devsoap.vaadinflow.extensions.VaadinFlowPluginExtension
import groovy.transform.PackageScope
import groovy.util.logging.Log
import io.github.classgraph.AnnotationInfo
import io.github.classgraph.ClassGraph
import io.github.classgraph.ClassInfo
import io.github.classgraph.ClassInfoList
import io.github.classgraph.ScanResult
import org.gradle.api.GradleException
import org.gradle.api.Project

import java.nio.file.Path
Expand Down Expand Up @@ -218,11 +220,18 @@ class ClassIntrospectionUtils {
* @return
* the values of the css imports
*/
static final Map<String,String> findCssImportsByRoute(ScanResult scan) {
Map<String, String> imports = [:]
static final Map<String,Map<String,String>> findCssImportsByRoute(ScanResult scan) {
Map<String, Map<String,String>> imports = [:]
List<String> processedClasses = []
scan.getClassesWithAnnotation(ROUTE_FQN).each { ClassInfo ci ->
findImportModulesByDependencies(ci, imports, CSS_IMPORT_FQN, processedClasses)
findImportModulesByDependencies(ci, imports, CSS_IMPORT_FQN, processedClasses) { info, a ->
[
'className' : info.name,
'include' : a.parameterValues.include?.value,
'id' : a.parameterValues.id?.value,
'target' : a.parameterValues.themeFor?.value
]
}
}
LOGGER.info("Scanned ${processedClasses.size()} classes.")
imports
Expand All @@ -237,16 +246,32 @@ class ClassIntrospectionUtils {
* @return
* the values of the css imports
*/
static final Map<String,String> findCssImportsByWhitelist(ScanResult scan) {
Map<String, String> imports = [:]
static final Map<String, Map<String,String>> findCssImportsByWhitelist(ScanResult scan) {
Map<String, Map<String,String>> imports = [:]
scan.getClassesWithAnnotation(CSS_IMPORT_FQN).collect { ClassInfo ci ->
ci.getAnnotationInfoRepeatable(CSS_IMPORT_FQN).each { AnnotationInfo a ->
imports[a.parameterValues.value.value.toString()] = ci.name
imports[a.parameterValues.value.value.toString()] = [
'className' : ci.name,
'include' : a.parameterValues.include?.value,
'id' : a.parameterValues.id?.value,
'target' : a.parameterValues.themeFor?.value
]
}
}
imports
}

static final Map<String, Map<String,String>> findCssImports(VaadinFlowPluginExtension vaadin, ScanResult scan) {
switch (vaadin.scanStrategy) {
case 'route':
return findCssImportsByRoute(scan)
case 'whitelist':
return findCssImportsByWhitelist(scan)
default:
throw new GradleException("Scan strategy $vaadin.scanStrategy has not been implemented.")
}
}

/**
* Find all classes which has an @Id filed annotation
*
Expand All @@ -269,18 +294,21 @@ class ClassIntrospectionUtils {
* the annotation to search for
* @param processedClasses
* the accumulated processedClasses
* @param valueGenerator
* the generator that generates the returned map values
*/
static final void findImportModulesByDependencies(ClassInfo info, Map<String, String> imports, String annotation,
List<String> processedClasses) {
static final <T> void findImportModulesByDependencies(ClassInfo info, Map<String, T> imports, String annotation,
List<String> processedClasses,
Closure<T> valueGenerator = { i, a -> i.name }) {
processedClasses << info.name
if (info.hasAnnotation(annotation)) {
info.getAnnotationInfoRepeatable(annotation).each { AnnotationInfo a ->
imports[a.parameterValues.value.value.toString()] = info.name
imports[a.parameterValues.value.value.toString()] = valueGenerator.call(info, a)
}
}
info.classDependencies.each { ClassInfo childInfo ->
if (!processedClasses.contains(childInfo.name)) {
findImportModulesByDependencies(childInfo, imports, annotation, processedClasses)
findImportModulesByDependencies(childInfo, imports, annotation, processedClasses, valueGenerator)
}
}
}
Expand Down

0 comments on commit b317fd4

Please sign in to comment.