generated from moderneinc/rewrite-recipe-starter
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add `KotlinTemplate` The `KotlinTemplate` class in this PR is an extension of `JavaTemplate` and replaces many of its internals so that `JavaTemplate` can be used to parse and template Kotlin code. As a demo have a look at `ReplaceCharToIntWithCode`. * Remove optional semicolon from template code * Copy some code from `JavaTemplate.Builder` * Implement `KotlinSubstitutions` and `KotlinBlockStatementTemplateGenerator` * Update to use `getTemplateClasspathDir()` * Simplify `KotlinSubstitutions.newArrayParameter()` * Add `TEMPLATE_INTERNAL_IMPORTS` imports * Polish * Remove no longer required `JavaTemplate` constructor argument * Align with latest upstream changes * Make `addClasspathEntry()` public --------- Co-authored-by: Kun Li <[email protected]>
- Loading branch information
1 parent
1b0c623
commit 2bdf2c6
Showing
9 changed files
with
386 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
src/main/java/org/openrewrite/kotlin/KotlinTemplate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.openrewrite.kotlin; | ||
|
||
import org.openrewrite.Cursor; | ||
import org.openrewrite.internal.StringUtils; | ||
import org.openrewrite.java.JavaTemplate; | ||
import org.openrewrite.java.internal.template.Substitutions; | ||
import org.openrewrite.java.tree.J; | ||
import org.openrewrite.java.tree.JavaCoordinates; | ||
import org.openrewrite.kotlin.internal.template.KotlinSubstitutions; | ||
import org.openrewrite.kotlin.internal.template.KotlinTemplateParser; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.function.Consumer; | ||
|
||
public class KotlinTemplate extends JavaTemplate { | ||
private KotlinTemplate(boolean contextSensitive, KotlinParser.Builder parser, String code, Set<String> imports, Consumer<String> onAfterVariableSubstitution, Consumer<String> onBeforeParseTemplate) { | ||
super( | ||
code, | ||
onAfterVariableSubstitution, | ||
new KotlinTemplateParser( | ||
contextSensitive, | ||
augmentClasspath(parser), | ||
onAfterVariableSubstitution, | ||
onBeforeParseTemplate, | ||
imports | ||
) | ||
); | ||
} | ||
|
||
private static KotlinParser.Builder augmentClasspath(KotlinParser.Builder parserBuilder) { | ||
return parserBuilder.addClasspathEntry(getTemplateClasspathDir()); | ||
} | ||
|
||
@Override | ||
protected Substitutions substitutions(Object[] parameters) { | ||
return new KotlinSubstitutions(getCode(), parameters); | ||
} | ||
|
||
public static <J2 extends J> J2 apply(String template, Cursor scope, JavaCoordinates coordinates, Object... parameters) { | ||
return builder(template).build().apply(scope, coordinates, parameters); | ||
} | ||
|
||
public static Builder builder(String code) { | ||
return new Builder(code); | ||
} | ||
|
||
public static boolean matches(String template, Cursor cursor) { | ||
return builder(template).build().matches(cursor); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class Builder extends JavaTemplate.Builder { | ||
|
||
private final String code; | ||
private final Set<String> imports = new HashSet<>(); | ||
|
||
private KotlinParser.Builder parser = KotlinParser.builder(); | ||
|
||
private Consumer<String> onAfterVariableSubstitution = s -> { | ||
}; | ||
private Consumer<String> onBeforeParseTemplate = s -> { | ||
}; | ||
|
||
Builder(String code) { | ||
super(code); | ||
this.code = code; | ||
} | ||
|
||
public Builder imports(String... fullyQualifiedTypeNames) { | ||
for (String typeName : fullyQualifiedTypeNames) { | ||
validateImport(typeName); | ||
this.imports.add("import " + typeName + "\n"); | ||
} | ||
return this; | ||
} | ||
|
||
private void validateImport(String typeName) { | ||
if (StringUtils.isBlank(typeName)) { | ||
throw new IllegalArgumentException("Imports must not be blank"); | ||
} else if (typeName.startsWith("import ")) { | ||
throw new IllegalArgumentException("Imports are expressed as fully-qualified names and should not include an \"import \" prefix"); | ||
} else if (typeName.endsWith(";") || typeName.endsWith("\n")) { | ||
throw new IllegalArgumentException("Imports are expressed as fully-qualified names and should not include a suffixed terminator"); | ||
} | ||
} | ||
|
||
Builder parser(KotlinParser.Builder parser) { | ||
this.parser = parser; | ||
return this; | ||
} | ||
|
||
public Builder doAfterVariableSubstitution(Consumer<String> afterVariableSubstitution) { | ||
this.onAfterVariableSubstitution = afterVariableSubstitution; | ||
return this; | ||
} | ||
|
||
public Builder doBeforeParseTemplate(Consumer<String> beforeParseTemplate) { | ||
this.onBeforeParseTemplate = beforeParseTemplate; | ||
return this; | ||
} | ||
|
||
public KotlinTemplate build() { | ||
return new KotlinTemplate(false, parser, code, imports, | ||
onAfterVariableSubstitution, onBeforeParseTemplate); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
.../java/org/openrewrite/kotlin/internal/template/KotlinBlockStatementTemplateGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.openrewrite.kotlin.internal.template; | ||
|
||
import org.openrewrite.Cursor; | ||
import org.openrewrite.java.internal.template.BlockStatementTemplateGenerator; | ||
import org.openrewrite.java.tree.Expression; | ||
import org.openrewrite.java.tree.J; | ||
import org.openrewrite.java.tree.JavaCoordinates; | ||
|
||
import java.util.Set; | ||
|
||
public class KotlinBlockStatementTemplateGenerator extends BlockStatementTemplateGenerator { | ||
public KotlinBlockStatementTemplateGenerator(Set<String> imports, boolean contextSensitive) { | ||
super(imports, contextSensitive); | ||
} | ||
|
||
@Override | ||
protected void contextFreeTemplate(Cursor cursor, J j, StringBuilder before, StringBuilder after) { | ||
if (!(j instanceof Expression)) { | ||
throw new IllegalArgumentException( | ||
"Kotlin templating is currently only implemented for context-free expressions and not for `" + j.getClass() + "` instances."); | ||
} | ||
|
||
before.insert(0, "class Template {\n"); | ||
before.append("var o : Object = "); | ||
after.append(";"); | ||
after.append("\n}"); | ||
|
||
before.insert(0, TEMPLATE_INTERNAL_IMPORTS); | ||
for (String anImport : imports) { | ||
before.insert(0, anImport); | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/main/java/org/openrewrite/kotlin/internal/template/KotlinSubstitutions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.openrewrite.kotlin.internal.template; | ||
|
||
import org.openrewrite.java.internal.template.Substitutions; | ||
import org.openrewrite.java.tree.JavaType; | ||
|
||
public class KotlinSubstitutions extends Substitutions { | ||
public KotlinSubstitutions(String code, Object[] parameters) { | ||
super(code, parameters); | ||
} | ||
|
||
@Override | ||
protected String newObjectParameter(String fqn, int index) { | ||
return "__P__./*__p" + index + "__*/p<" + fqn + ">()"; | ||
} | ||
|
||
@Override | ||
protected String newPrimitiveParameter(String fqn, int index) { | ||
return newObjectParameter(fqn, index); | ||
} | ||
|
||
@Override | ||
protected String newArrayParameter(JavaType elemType, int dimensions, int index) { | ||
// generate literal of the form: `arrayOf(arrayOf<String?>())` | ||
StringBuilder builder = new StringBuilder("/*__p" + index + "__*/"); | ||
for (int i = 0; i < dimensions; i++) { | ||
builder.append("arrayOf"); | ||
if (i < dimensions - 1) { | ||
builder.append('('); | ||
} | ||
} | ||
builder.append('<'); | ||
if (elemType instanceof JavaType.Primitive) { | ||
builder.append(((JavaType.Primitive) elemType).getKeyword()); | ||
} else if (elemType instanceof JavaType.FullyQualified) { | ||
builder.append(((JavaType.FullyQualified) elemType).getFullyQualifiedName().replace("$", ".")); | ||
} | ||
builder.append(">("); | ||
for (int i = 0; i < dimensions; i++) { | ||
builder.append(')'); | ||
} | ||
return builder.toString(); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
src/main/java/org/openrewrite/kotlin/internal/template/KotlinTemplateParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.openrewrite.kotlin.internal.template; | ||
|
||
import org.openrewrite.java.internal.template.AnnotationTemplateGenerator; | ||
import org.openrewrite.java.internal.template.JavaTemplateParser; | ||
import org.openrewrite.kotlin.KotlinParser; | ||
|
||
import java.util.Set; | ||
import java.util.function.Consumer; | ||
|
||
public class KotlinTemplateParser extends JavaTemplateParser { | ||
public KotlinTemplateParser(boolean contextSensitive, KotlinParser.Builder parser, Consumer<String> onAfterVariableSubstitution, Consumer<String> onBeforeParseTemplate, Set<String> imports) { | ||
super( | ||
parser, | ||
onAfterVariableSubstitution, | ||
onBeforeParseTemplate, | ||
imports, | ||
contextSensitive, | ||
new KotlinBlockStatementTemplateGenerator(imports, contextSensitive), | ||
new AnnotationTemplateGenerator(imports) | ||
); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/org/openrewrite/kotlin/internal/template/package-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
@NonNullApi | ||
@NonNullFields | ||
package org.openrewrite.kotlin.internal.template; | ||
|
||
import org.openrewrite.internal.lang.NonNullApi; | ||
import org.openrewrite.internal.lang.NonNullFields; |
21 changes: 21 additions & 0 deletions
21
src/main/java/org/openrewrite/kotlin/marker/package-info.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright 2023 the original author or authors. | ||
* <p> | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
@NonNullApi | ||
@NonNullFields | ||
package org.openrewrite.kotlin.marker; | ||
|
||
import org.openrewrite.internal.lang.NonNullApi; | ||
import org.openrewrite.internal.lang.NonNullFields; |
Oops, something went wrong.