mirror of https://github.com/FabricMC/yarn.git
Add tests and task
This commit is contained in:
parent
48cf4b54d0
commit
2a7aa1e312
58
build.gradle
58
build.gradle
|
@ -60,14 +60,6 @@ configurations {
|
|||
}
|
||||
javadocClasspath
|
||||
decompileClasspath
|
||||
mappingPoetJar {
|
||||
transitive = false
|
||||
}
|
||||
mappingPoet {
|
||||
extendsFrom mappingPoetJar
|
||||
extendsFrom asm
|
||||
transitive = true
|
||||
}
|
||||
}
|
||||
|
||||
def unpickMetaFile = file("unpick-definitions/unpick.json")
|
||||
|
@ -81,7 +73,6 @@ dependencies {
|
|||
javadocClasspath "com.google.code.findbugs:jsr305:3.0.2" // for some other jsr annotations
|
||||
decompileClasspath "net.fabricmc:cfr:${project.cfr_version}"
|
||||
decompileClasspath "org.vineflower:vineflower:${project.vineflower_version}"
|
||||
mappingPoetJar "net.fabricmc:mappingpoet:${project.mappingpoet_version}"
|
||||
asm "org.ow2.asm:asm:${project.asm_version}"
|
||||
asm "org.ow2.asm:asm-tree:${project.asm_version}"
|
||||
asm "org.ow2.asm:asm-commons:${project.asm_version}"
|
||||
|
@ -102,6 +93,7 @@ import cuchaz.enigma.command.CheckMappingsCommand
|
|||
import net.fabricmc.filament.task.MapJarTask
|
||||
import net.fabricmc.filament.task.DownloadTask
|
||||
import net.fabricmc.filament.task.UnpickJarTask
|
||||
import net.fabricmc.filament.task.MappingPoetTask;
|
||||
import net.fabricmc.filament.task.base.WithFileInput
|
||||
import net.fabricmc.filament.task.base.WithFileOutput
|
||||
import net.fabricmc.filament.task.enigma.MapSpecializedMethodsTask
|
||||
|
@ -430,20 +422,12 @@ tasks.register('syncDependencies', Sync) {
|
|||
}
|
||||
|
||||
def fakeSourceDir = file(".gradle/temp/fakeSource")
|
||||
tasks.register('genFakeSource', JavaExec) {
|
||||
dependsOn mergeV2, mapNamedJar, syncDependencies
|
||||
tasks.register('genFakeSource', MappingPoetTask) {
|
||||
group = "javadoc generation"
|
||||
|
||||
inputs.file mergeV2.output
|
||||
inputs.file mapNamedJar.output
|
||||
inputs.dir mcLibsDir
|
||||
|
||||
outputs.dir fakeSourceDir
|
||||
|
||||
mainClass = "net.fabricmc.mappingpoet.Main"
|
||||
classpath configurations.mappingPoet
|
||||
// use merged v2 so we have all namespaces in jd
|
||||
args mergeV2.outputFile.getAbsolutePath(), mapNamedJar.outputFile.getAbsolutePath(), fakeSourceDir.getAbsolutePath(), mcLibsDir.getAbsolutePath()
|
||||
mappings = mergeV2.output
|
||||
minecraftJar = mapNamedJar.output
|
||||
libraries.from(minecraftLibraries)
|
||||
output = fakeSourceDir
|
||||
}
|
||||
|
||||
def decompileOutput = layout.buildDirectory.file("namedSrc")
|
||||
|
@ -480,8 +464,6 @@ javadoc {
|
|||
dependsOn genFakeSource
|
||||
group = "javadoc generation"
|
||||
|
||||
def mappingPoetJar = project.provider { zipTree configurations.mappingPoetJar.singleFile }
|
||||
|
||||
failOnError = false
|
||||
maxMemory = '2G'
|
||||
|
||||
|
@ -498,7 +480,7 @@ javadoc {
|
|||
'implSpec:a:Implementation Requirements:',
|
||||
'implNote:a:Implementation Note:'
|
||||
)
|
||||
taglets "net.fabricmc.mappingpoet.jd.MappingTaglet"
|
||||
taglets "net.fabricmc.filament.mappingpoet.jd.MappingTaglet"
|
||||
// taglet path, header, extra stylesheet settings deferred
|
||||
it.use()
|
||||
|
||||
|
@ -537,26 +519,13 @@ javadoc {
|
|||
source fileTree(fakeSourceDir) + sourceSets.constants.allJava + sourceSets.packageDocs.allJava
|
||||
classpath = configurations.javadocClasspath.plus minecraftLibraries
|
||||
|
||||
def fs = project.services.get(FileSystemOperations.class)
|
||||
def outputDir = javadoc.destinationDir
|
||||
// TODO how to do this?
|
||||
// def tagletClasspath = configurations.mappingPoet.files.toList()
|
||||
|
||||
doLast {
|
||||
fs.copy {
|
||||
from mappingPoetJar
|
||||
include "copy_on_click.js"
|
||||
into outputDir
|
||||
}
|
||||
}
|
||||
|
||||
def tagletClasspath = configurations.mappingPoet.files.toList()
|
||||
|
||||
doFirst {
|
||||
// lazy setting
|
||||
options {
|
||||
tagletPath tagletClasspath
|
||||
header mappingPoetJar.get().filter { it.name == 'javadoc_header.txt' }.singleFile.text.trim() // cannot include line breaks
|
||||
addFileOption "-add-stylesheet", mappingPoetJar.get().filter { it.name == 'forms.css' }.singleFile
|
||||
}
|
||||
options {
|
||||
// tagletPath tagletClasspath
|
||||
header file("gradle/javadoc/header.txt").text.trim() // cannot include line breaks
|
||||
addFileOption "-add-stylesheet", file("gradle/javadoc/forms.css")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,6 +534,7 @@ tasks.register('javadocJar', Jar) {
|
|||
group = "javadoc generation"
|
||||
|
||||
from javadoc.destinationDir
|
||||
from file("gradle/javadoc/copy_on_click.js")
|
||||
|
||||
archiveVersion.set yarnVersion
|
||||
archiveClassifier = 'javadoc'
|
||||
|
|
|
@ -36,7 +36,6 @@ dependencies {
|
|||
implementation "net.fabricmc.unpick:unpick-format-utils:$properties.unpick_version"
|
||||
implementation "net.fabricmc.unpick:unpick-cli:$properties.unpick_version"
|
||||
implementation "net.fabricmc:tiny-remapper:$properties.tiny_remapper_version"
|
||||
implementation "net.fabricmc:mappingpoet:$properties.mappingpoet_version"
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4.2'
|
||||
implementation 'net.fabricmc:mapping-io:0.5.1'
|
||||
implementation 'net.fabricmc:javapoet:0.1.1'
|
||||
|
|
|
@ -16,17 +16,11 @@
|
|||
|
||||
package net.fabricmc.filament.mappingpoet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
@ -50,49 +44,11 @@ import org.objectweb.asm.tree.InnerClassNode;
|
|||
import net.fabricmc.filament.mappingpoet.Environment.ClassNamePointer;
|
||||
import net.fabricmc.filament.mappingpoet.Environment.NestedClassInfo;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 3 && args.length != 4) {
|
||||
System.out.println("<mappings> <inputJar> <outputDir> [<librariesDir>]");
|
||||
return;
|
||||
}
|
||||
|
||||
Path mappings = Paths.get(args[0]);
|
||||
Path inputJar = Paths.get(args[1]);
|
||||
Path outputDirectory = Paths.get(args[2]);
|
||||
Path librariesDir = args.length < 4 ? null : Paths.get(args[3]);
|
||||
|
||||
try {
|
||||
if (Files.exists(outputDirectory)) {
|
||||
try (var stream = Files.walk(outputDirectory)) {
|
||||
stream.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
.forEach(File::delete);
|
||||
}
|
||||
}
|
||||
|
||||
Files.createDirectories(outputDirectory);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
if (!Files.exists(mappings)) {
|
||||
System.out.println("could not find mappings");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Files.exists(inputJar)) {
|
||||
System.out.println("could not find input jar");
|
||||
return;
|
||||
}
|
||||
|
||||
generate(mappings, inputJar, outputDirectory, librariesDir);
|
||||
}
|
||||
|
||||
public static void generate(Path mappings, Path inputJar, Path outputDirectory, Path librariesDir) {
|
||||
public class MappingPoet {
|
||||
public static void generate(Path mappings, Path inputJar, Path outputDirectory, List<Path> libraries) {
|
||||
final MappingsStore mapping = new MappingsStore(mappings);
|
||||
Map<String, ClassBuilder> classes = new HashMap<>();
|
||||
forEachClass(inputJar, (classNode, environment) -> writeClass(mapping, classNode, classes, environment), librariesDir);
|
||||
forEachClass(inputJar, (classNode, environment) -> writeClass(mapping, classNode, classes, environment), libraries);
|
||||
|
||||
for (ClassBuilder classBuilder : classes.values()) {
|
||||
String name = classBuilder.getClassName();
|
||||
|
@ -110,7 +66,7 @@ public class Main {
|
|||
}
|
||||
}
|
||||
|
||||
private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, Path librariesDir) {
|
||||
private static void forEachClass(Path jar, ClassNodeConsumer classNodeConsumer, List<Path> libraries) {
|
||||
List<ClassNode> classes = new ArrayList<>();
|
||||
Map<String, Collection<String>> supers = new HashMap<>();
|
||||
Set<String> sealedClasses = new HashSet<>(); // their subclsses/impls need non-sealed modifier
|
||||
|
@ -118,8 +74,8 @@ public class Main {
|
|||
Map<String, Environment.NestedClassInfo> nestedClasses = new ConcurrentHashMap<>();
|
||||
Map<String, ClassNamePointer> classNames = new ConcurrentHashMap<>();
|
||||
|
||||
if (librariesDir != null) {
|
||||
scanNestedClasses(classNames, nestedClasses, librariesDir);
|
||||
if (libraries.isEmpty()) {
|
||||
scanNestedClasses(classNames, nestedClasses, libraries);
|
||||
}
|
||||
|
||||
try (JarFile jarFile = new JarFile(jar.toFile())) {
|
||||
|
@ -178,44 +134,35 @@ public class Main {
|
|||
}
|
||||
}
|
||||
|
||||
private static void scanNestedClasses(Map<String, ClassNamePointer> classNames, Map<String, Environment.NestedClassInfo> instanceInnerClasses, Path librariesDir) {
|
||||
private static void scanNestedClasses(Map<String, ClassNamePointer> classNames, Map<String, Environment.NestedClassInfo> instanceInnerClasses, List<Path> libraries) {
|
||||
try {
|
||||
Files.walkFileTree(librariesDir, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (!file.getFileName().toString().endsWith(".jar")) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
for (Path library : libraries) {
|
||||
try (JarFile jarFile = new JarFile(library.toFile())) {
|
||||
Enumeration<JarEntry> entryEnumerator = jarFile.entries();
|
||||
|
||||
try (JarFile jarFile = new JarFile(file.toFile())) {
|
||||
Enumeration<JarEntry> entryEnumerator = jarFile.entries();
|
||||
while (entryEnumerator.hasMoreElements()) {
|
||||
JarEntry entry = entryEnumerator.nextElement();
|
||||
|
||||
while (entryEnumerator.hasMoreElements()) {
|
||||
JarEntry entry = entryEnumerator.nextElement();
|
||||
if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
|
||||
continue;
|
||||
}
|
||||
try (InputStream is = jarFile.getInputStream(entry)) {
|
||||
ClassReader reader = new ClassReader(is);
|
||||
reader.accept(new ClassVisitor(Opcodes.ASM9) {
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String simpleName, int access) {
|
||||
instanceInnerClasses.put(name, new NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName));
|
||||
|
||||
try (InputStream is = jarFile.getInputStream(entry)) {
|
||||
ClassReader reader = new ClassReader(is);
|
||||
reader.accept(new ClassVisitor(Opcodes.ASM9) {
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String simpleName, int access) {
|
||||
instanceInnerClasses.put(name, new NestedClassInfo(outerName, !Modifier.isStatic(access), simpleName));
|
||||
|
||||
if (outerName != null) {
|
||||
classNames.put(name, new ClassNamePointer(simpleName, outerName));
|
||||
}
|
||||
if (outerName != null) {
|
||||
classNames.put(name, new ClassNamePointer(simpleName, outerName));
|
||||
}
|
||||
}, ClassReader.SKIP_CODE);
|
||||
}
|
||||
}
|
||||
}, ClassReader.SKIP_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
|
@ -225,7 +172,7 @@ public class Main {
|
|||
String javaBinary = internalName.replace('/', '.');
|
||||
|
||||
try {
|
||||
Class<?> c = Class.forName(javaBinary, false, Main.class.getClassLoader());
|
||||
Class<?> c = Class.forName(javaBinary, false, MappingPoet.class.getClassLoader());
|
||||
return !Modifier.isStatic(c.getModifiers()) && c.getDeclaringClass() != null;
|
||||
} catch (Throwable ex) {
|
||||
return false;
|
|
@ -0,0 +1,35 @@
|
|||
package net.fabricmc.filament.task;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import net.fabricmc.filament.mappingpoet.MappingPoet;
|
||||
|
||||
public abstract class MappingPoetTask extends DefaultTask {
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getMappings();
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getMinecraftJar();
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getLibraries();
|
||||
@OutputDirectory
|
||||
public abstract DirectoryProperty getOutput();
|
||||
|
||||
@TaskAction
|
||||
public void run() {
|
||||
MappingPoet.generate(
|
||||
getMappings().get().getAsFile().toPath(),
|
||||
getMinecraftJar().get().getAsFile().toPath(),
|
||||
getOutput().get().getAsFile().toPath(),
|
||||
getLibraries().getFiles().stream().map(File::toPath).toList()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2020 FabricMC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 net.fabricmc.filament.test.mappingpoet;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Documented
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BorkAnno {
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) 2020 FabricMC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 net.fabricmc.filament.test.mappingpoet;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import com.squareup.javapoet.ArrayTypeName;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import com.squareup.javapoet.WildcardTypeName;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
|
||||
import net.fabricmc.filament.mappingpoet.signature.ClassSignature;
|
||||
import net.fabricmc.filament.mappingpoet.signature.MethodSignature;
|
||||
import net.fabricmc.filament.mappingpoet.signature.PoetClassMethodSignatureVisitor;
|
||||
import net.fabricmc.filament.mappingpoet.signature.PoetTypeSignatureWriter;
|
||||
import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationBank;
|
||||
import net.fabricmc.filament.mappingpoet.signature.TypeAnnotationMapping;
|
||||
import net.fabricmc.filament.mappingpoet.Signatures;
|
||||
|
||||
public class SignaturesTest {
|
||||
@Test
|
||||
public void testRandomMapType() {
|
||||
//signature Ljava/util/Map<Ljava/util/Map$Entry<[[Ljava/lang/String;[Ljava/util/List<[I>;>;[[[D>;
|
||||
//Map<Map.Entry<String[][], List<int[]>[]>, double[][][]> map = new HashMap<>();
|
||||
String signature = "Ljava/util/Map<Ljava/util/Map$Entry<[[Ljava/lang/String;[Ljava/util/List<[I>;>;[[[D>;";
|
||||
Map.Entry<Integer, TypeName> result = Signatures.parseParameterizedType(signature, 0);
|
||||
|
||||
Assertions.assertEquals(85, result.getKey().intValue());
|
||||
Assertions.assertEquals("java.util.Map<java.util.Map.Entry<java.lang.String[][], java.util.List<int[]>[]>, double[][][]>", result.getValue().toString());
|
||||
|
||||
PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false);
|
||||
new SignatureReader(signature).acceptType(writer);
|
||||
Assertions.assertEquals("java.util.Map<java.util.Map.Entry<java.lang.String[][], java.util.List<int[]>[]>, double[][][]>", writer.compute().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrazyOne() {
|
||||
String classSignature = "<B::Ljava/util/Comparator<-TA;>;C:Ljava/lang/ClassLoader;:Ljava/lang/Iterable<*>;>Ljava/lang/Object;";
|
||||
Map.Entry<Integer, TypeName> result = Signatures.parseParameterizedType(classSignature, 4);
|
||||
Assertions.assertEquals(32, result.getKey().intValue());
|
||||
Assertions.assertEquals("java.util.Comparator<? super A>", result.getValue().toString());
|
||||
|
||||
result = Signatures.parseParameterizedType(classSignature, 34);
|
||||
Assertions.assertEquals(57, result.getKey().intValue());
|
||||
Assertions.assertEquals("java.lang.ClassLoader", result.getValue().toString());
|
||||
|
||||
result = Signatures.parseParameterizedType(classSignature, 58);
|
||||
Assertions.assertEquals(81, result.getKey().intValue());
|
||||
Assertions.assertEquals("java.lang.Iterable<?>", result.getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void soo() {
|
||||
TestOuter<Integer>.Inner<Comparator<Integer>, URLClassLoader>.ExtraInner<UnaryOperator<Map<int[][], BiFunction<Comparator<Integer>, Integer, URLClassLoader>>>> local = new TestOuter<Integer>().new Inner<Comparator<Integer>, URLClassLoader>().new ExtraInner<UnaryOperator<Map<int[][], BiFunction<Comparator<Integer>, Integer, URLClassLoader>>>>();
|
||||
local.hashCode();
|
||||
|
||||
// signature Lnet/fabricmc/mappingpoet/TestOuter<Ljava/lang/Integer;>.Inner<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/net/URLClassLoader;>.ExtraInner<Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/lang/Integer;Ljava/net/URLClassLoader;>;>;>;>;
|
||||
String signature = "Lnet/fabricmc/mappingpoet/TestOuter<Ljava/lang/Integer;>.Inner<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/net/URLClassLoader;>.ExtraInner<Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/lang/Integer;Ljava/net/URLClassLoader;>;>;>;>;";
|
||||
Map.Entry<Integer, TypeName> result = Signatures.parseParameterizedType(signature, 0);
|
||||
|
||||
Assertions.assertEquals(322, result.getKey().intValue());
|
||||
Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter<java.lang.Integer>.Inner<java.util.Comparator<java.lang.Integer>, java.net.URLClassLoader>.ExtraInner<java.util.function.UnaryOperator<java.util.Map<int[][], java.util.function.BiFunction<java.util.Comparator<java.lang.Integer>, java.lang.Integer, java.net.URLClassLoader>>>>", result.getValue().toString());
|
||||
|
||||
PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false);
|
||||
new SignatureReader(signature).acceptType(writer);
|
||||
Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter<java.lang.Integer>.Inner<java.util.Comparator<java.lang.Integer>, java.net.URLClassLoader>.ExtraInner<java.util.function.UnaryOperator<java.util.Map<int[][], java.util.function.BiFunction<java.util.Comparator<java.lang.Integer>, java.lang.Integer, java.net.URLClassLoader>>>>", writer.compute().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrSoo() {
|
||||
@SuppressWarnings("unchecked")
|
||||
TestOuter<Integer>.Inner<Comparator<Integer>, URLClassLoader>.ExtraInner<UnaryOperator<Map<int[][], BiFunction<Comparator<Integer>, Integer, URLClassLoader>>>>[][] arr = (TestOuter<Integer>.Inner<Comparator<Integer>, URLClassLoader>.ExtraInner<UnaryOperator<Map<int[][], BiFunction<Comparator<Integer>, Integer, URLClassLoader>>>>[][]) new TestOuter<?>.Inner<?, ?>.ExtraInner<?>[0][];
|
||||
arr.toString();
|
||||
// signature [[Lnet/fabricmc/mappingpoet/TestOuter<Ljava/lang/Integer;>.Inner<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/net/URLClassLoader;>.ExtraInner<Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/lang/Integer;Ljava/net/URLClassLoader;>;>;>;>;
|
||||
String arraySignature = "[[Lnet/fabricmc/mappingpoet/TestOuter<Ljava/lang/Integer;>.Inner<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/net/URLClassLoader;>.ExtraInner<Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<Ljava/util/Comparator<Ljava/lang/Integer;>;Ljava/lang/Integer;Ljava/net/URLClassLoader;>;>;>;>;";
|
||||
Map.Entry<Integer, TypeName> result = Signatures.parseParameterizedType(arraySignature, 0);
|
||||
|
||||
Assertions.assertEquals(324, result.getKey().intValue());
|
||||
Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter<java.lang.Integer>.Inner<java.util.Comparator<java.lang.Integer>, java.net.URLClassLoader>.ExtraInner<java.util.function.UnaryOperator<java.util.Map<int[][], java.util.function.BiFunction<java.util.Comparator<java.lang.Integer>, java.lang.Integer, java.net.URLClassLoader>>>>[][]", result.getValue().toString());
|
||||
|
||||
PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false);
|
||||
new SignatureReader(arraySignature).acceptType(writer);
|
||||
Assertions.assertEquals("net.fabricmc.mappingpoet.TestOuter<java.lang.Integer>.Inner<java.util.Comparator<java.lang.Integer>, java.net.URLClassLoader>.ExtraInner<java.util.function.UnaryOperator<java.util.Map<int[][], java.util.function.BiFunction<java.util.Comparator<java.lang.Integer>, java.lang.Integer, java.net.URLClassLoader>>>>[][]", writer.compute().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassDeeSignature() {
|
||||
// signature <D::Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<TB;TA;TC;>;>;>;>Ljava/lang/Object;
|
||||
String classSig = "<D::Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<TB;TA;TC;>;>;>;>Ljava/lang/Object;";
|
||||
Map.Entry<Integer, TypeName> dBound = Signatures.parseParameterizedType(classSig, 4);
|
||||
|
||||
Assertions.assertEquals(102, dBound.getKey().intValue());
|
||||
Assertions.assertEquals("java.util.function.UnaryOperator<java.util.Map<int[][], java.util.function.BiFunction<B, A, C>>>", dBound.getValue().toString());
|
||||
|
||||
ClassSignature parsed = Signatures.parseClassSignature(classSig);
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics());
|
||||
Assertions.assertEquals(ClassName.OBJECT, parsed.superclass());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClassDeeSignatureVisitor() {
|
||||
// signature <D::Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<TB;TA;TC;>;>;>;>Ljava/lang/Object;
|
||||
String classSig = "<D::Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<TB;TA;TC;>;>;>;>Ljava/lang/Object;";
|
||||
|
||||
PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, true);
|
||||
new SignatureReader(classSig).accept(visitor);
|
||||
ClassSignature parsed = visitor.collectClass();
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("D")), parsed.generics());
|
||||
Assertions.assertEquals(ClassName.OBJECT, parsed.superclass());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.superinterfaces());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionIntFunctionToArraySignature() {
|
||||
// signature <T:Ljava/lang/Object;>(Ljava/util/function/IntFunction<[TT;>;)[TT;
|
||||
String methodSignature = "<T:Ljava/lang/Object;>(Ljava/util/function/IntFunction<[TT;>;)[TT;";
|
||||
MethodSignature parsed = Signatures.parseMethodSignature(methodSignature);
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics());
|
||||
Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown());
|
||||
Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(ClassName.get(IntFunction.class), ArrayTypeName.of(TypeVariableName.get("T")))), parsed.parameters());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionArrayToArraySignature() {
|
||||
// signature <T:Ljava/lang/Object;>([TT;)[TT;
|
||||
String methodSignature = "<T:Ljava/lang/Object;>([TT;)[TT;";
|
||||
MethodSignature parsed = Signatures.parseMethodSignature(methodSignature);
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics());
|
||||
Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown());
|
||||
Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionArrayToArraySignatureVisitor() {
|
||||
// signature <T:Ljava/lang/Object;>([TT;)[TT;
|
||||
String methodSignature = "<T:Ljava/lang/Object;>([TT;)[TT;";
|
||||
PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false);
|
||||
new SignatureReader(methodSignature).accept(visitor);
|
||||
MethodSignature parsed = visitor.collectMethod();
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("T")), parsed.generics());
|
||||
Assertions.assertEquals(ArrayTypeName.of(TypeVariableName.get("T")), parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown());
|
||||
Assertions.assertIterableEquals(Collections.singleton(ArrayTypeName.of(TypeVariableName.get("T"))), parsed.parameters());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTweakLastSignature() {
|
||||
// signature (Ljava/util/function/UnaryOperator<Lcom/squareup/javapoet/TypeName;>;)V
|
||||
String methodSignature = "(Ljava/util/function/UnaryOperator<Lcom/squareup/javapoet/TypeName;>;)V";
|
||||
MethodSignature parsed = Signatures.parseMethodSignature(methodSignature);
|
||||
Assertions.assertTrue(parsed.generics().isEmpty());
|
||||
Assertions.assertEquals(TypeName.VOID, parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown());
|
||||
ClassName unaryOperatorClass = ClassName.get(UnaryOperator.class);
|
||||
ClassName typeNameClass = ClassName.get(TypeName.class);
|
||||
Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTweakLastSignatureVisitor() {
|
||||
// signature (Ljava/util/function/UnaryOperator<Lcom/squareup/javapoet/TypeName;>;)V
|
||||
String methodSignature = "(Ljava/util/function/UnaryOperator<Lcom/squareup/javapoet/TypeName;>;)V";
|
||||
PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false);
|
||||
new SignatureReader(methodSignature).accept(visitor);
|
||||
MethodSignature parsed = visitor.collectMethod();
|
||||
Assertions.assertTrue(parsed.generics().isEmpty());
|
||||
Assertions.assertEquals(TypeName.VOID, parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.emptyList(), parsed.thrown());
|
||||
ClassName unaryOperatorClass = ClassName.get(UnaryOperator.class);
|
||||
ClassName typeNameClass = ClassName.get(TypeName.class);
|
||||
Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(unaryOperatorClass, typeNameClass)), parsed.parameters());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckHeadSignature() {
|
||||
// signature <E:Ljava/lang/Throwable;>(Lnet/fabricmc/filament/mappingpoet/Signatures$HeadChecker<TE;>;)V^TE;
|
||||
String raw = "<E:Ljava/lang/Throwable;>(Lnet/fabricmc/filament/mappingpoet/Signatures$HeadChecker<TE;>;)V^TE;";
|
||||
MethodSignature parsed = Signatures.parseMethodSignature(raw);
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics());
|
||||
ClassName headCheckerClass = ClassName.get(Signatures.class).nestedClass("HeadChecker");
|
||||
Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters());
|
||||
Assertions.assertEquals(TypeName.VOID, parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckHeadSignatureVisitor() {
|
||||
// signature <E:Ljava/lang/Throwable;>(Lnet/fabricmc/filament/mappingpoet/Signatures$HeadChecker<TE;>;)V^TE;
|
||||
String raw = "<E:Ljava/lang/Throwable;>(Lnet/fabricmc/filament/mappingpoet/Signatures$HeadChecker<TE;>;)V^TE;";
|
||||
PoetClassMethodSignatureVisitor visitor = new PoetClassMethodSignatureVisitor(TypeAnnotationMapping.EMPTY, s -> false, false);
|
||||
new SignatureReader(raw).accept(visitor);
|
||||
MethodSignature parsed = visitor.collectMethod();
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E", ClassName.get(Throwable.class))), parsed.generics());
|
||||
ClassName headCheckerClass = ClassName.get(Signatures.class).nestedClass("HeadChecker");
|
||||
Assertions.assertIterableEquals(Collections.singleton(ParameterizedTypeName.get(headCheckerClass, TypeVariableName.get("E"))), parsed.parameters());
|
||||
Assertions.assertEquals(TypeName.VOID, parsed.result());
|
||||
Assertions.assertIterableEquals(Collections.singleton(TypeVariableName.get("E")), parsed.thrown());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBrokenVariantSettingSignature() {
|
||||
// Ljava/util/Map<Lnet/minecraft/data/client/model/VariantSetting<*>;Lnet/minecraft/data/client/model/VariantSetting<*>.Value;>;
|
||||
String signature = "Ljava/util/Map<Lnet/minecraft/data/client/model/VariantSetting<*>;Lnet/minecraft/data/client/model/VariantSetting<*>.Value;>;";
|
||||
Map.Entry<Integer, TypeName> parsed = Signatures.parseParameterizedType(signature, 0);
|
||||
Assertions.assertEquals(125, parsed.getKey().intValue());
|
||||
ClassName variantSettingClass = ClassName.get("net.minecraft.data.client.model", "VariantSetting");
|
||||
ParameterizedTypeName wildcardVariantSetting = ParameterizedTypeName.get(variantSettingClass, WildcardTypeName.subtypeOf(TypeName.OBJECT));
|
||||
ParameterizedTypeName valueClass = wildcardVariantSetting.nestedClass("Value");
|
||||
ClassName mapClass = ClassName.get(Map.class);
|
||||
ParameterizedTypeName genericMap = ParameterizedTypeName.get(mapClass, wildcardVariantSetting, valueClass);
|
||||
Assertions.assertEquals(genericMap, parsed.getValue());
|
||||
|
||||
PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false);
|
||||
new SignatureReader(signature).acceptType(writer);
|
||||
Assertions.assertEquals(genericMap, writer.compute());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaticOuters() {
|
||||
Outer.MiddleStatic.@TestAnno InnerStatic instance = null;
|
||||
|
||||
// https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-4.html#jvms-4.7.20.2-220-B-A.1
|
||||
Outer.@TestAnno("a") MiddleStatic<@TestAnno("b") Object>.@TestAnno("c") Inner<@TestAnno("d") Integer> instance2 = new Outer.MiddleStatic<>().new Inner<Integer>();
|
||||
|
||||
String input = "Lnet/fabricmc/mappingpoet/Outer$MiddleStatic<Ljava/lang/Object;>.Inner<Ljava/lang/Integer;>;";
|
||||
|
||||
TypeName name = Signatures.parseFieldSignature(input);
|
||||
Assertions.assertEquals("net.fabricmc.mappingpoet.Outer.MiddleStatic<java.lang.Object>.Inner<java.lang.Integer>", name.toString());
|
||||
|
||||
PoetTypeSignatureWriter writer = new PoetTypeSignatureWriter(TypeAnnotationBank.EMPTY, s -> false);
|
||||
new SignatureReader(input).acceptType(writer);
|
||||
Assertions.assertEquals(name, writer.compute());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2020 FabricMC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 net.fabricmc.filament.test.mappingpoet;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE, ElementType.FIELD})
|
||||
public @interface TestAnno {
|
||||
String value() default "";
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2020 FabricMC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 net.fabricmc.filament.test.mappingpoet;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
enum StupidEnum {
|
||||
FIRST,
|
||||
@TestAnno
|
||||
SECOND;
|
||||
}
|
||||
|
||||
// signature <A::Ljava/lang/Comparable<-TA;>;>Ljava/lang/Object;
|
||||
public class TestOuter<A extends Comparable<? super A>> {
|
||||
// signature <B::Ljava/util/Comparator<-TA;>;C:Ljava/lang/ClassLoader;:Ljava/lang/Iterable<*>;>Ljava/lang/Object;
|
||||
class Inner<B extends Comparator<? super A>, C extends ClassLoader & AutoCloseable> {
|
||||
// signature <D::Ljava/util/function/UnaryOperator<Ljava/util/Map<[[ILjava/util/function/BiFunction<TB;TA;TC;>;>;>;>Ljava/lang/Object;
|
||||
class ExtraInner<D extends UnaryOperator<Map<int[][], BiFunction<B, A, C>>>> {
|
||||
ExtraInner(Inner<B, C> Inner.this) {
|
||||
// constructor receiver example. Notice 'this' cannot receive parameter annos
|
||||
}
|
||||
|
||||
void work(@TestAnno("on extra inner")ExtraInner<D> this, Inner<@TestAnno("pig") B, C> @TestAnno("lion") [][] @TestAnno("rat") [] arr) {
|
||||
}
|
||||
|
||||
void work2(ExtraInner<D> this) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Outer {
|
||||
void eat(@BorkAnno @TestAnno MiddleTwo.InnerThree<Integer> apple) {
|
||||
}
|
||||
|
||||
void eat(@BorkAnno MiddleStatic.@TestAnno InnerStatic apple) {
|
||||
}
|
||||
|
||||
static class MiddleStatic<T> {
|
||||
static class InnerStatic {
|
||||
}
|
||||
|
||||
class Inner<U> {
|
||||
}
|
||||
}
|
||||
|
||||
class MiddleTwo {
|
||||
class InnerThree<E> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OuterTwo<T> {
|
||||
static class InnerOne<G> {
|
||||
class InnerTwo {
|
||||
InnerTwo(InnerOne<G> InnerOne.this) {
|
||||
}
|
||||
|
||||
void called(InnerTwo this, InnerTwo other) {
|
||||
}
|
||||
|
||||
class NestedThree<W> {
|
||||
void work(NestedThree<W> this, NestedThree<W> other) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InnerTwo {
|
||||
class NestedThree<W> {
|
||||
void workSelf(@TestAnno("on myself!")NestedThree<@TestAnno("on my W") W> this) {
|
||||
}
|
||||
|
||||
void workSelf1(NestedThree<@TestAnno("on my W only") W> this) {
|
||||
}
|
||||
|
||||
void workSelf2(@TestAnno("on myself only")NestedThree<W> this) {
|
||||
}
|
||||
|
||||
void work(@TestAnno("on myself!")NestedThree<@TestAnno("on my W") W> this, NestedThree<@TestAnno("on their W") W> other) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
tiny 2 0 intermediary official named
|
||||
notice This is an example to test functionalities!
|
||||
c net/fabricmc/mappingpoet/Outer a net/fabricmc/mappingpoet/Outer
|
||||
m (Lnet/fabricmc/mappingpoet/Outer$MiddleTwo$InnerThree;)V eaten ate eat
|
||||
c net/hackingmc/fightingpoet/ZombieTest b net/fabricmc/mappingpoet/SignaturesTest
|
|
@ -13,7 +13,6 @@ asm_version=9.6
|
|||
# Javadoc generation/linking
|
||||
fabric_loader_version=0.15.10
|
||||
jetbrains_annotations_version=24.1.0
|
||||
mappingpoet_version=0.4.2
|
||||
|
||||
# Build logic
|
||||
tiny_remapper_version=0.10.3
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2020 FabricMC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
document.onreadystatechange = function() {
|
||||
if(document.readyState == "complete") {
|
||||
const items = document.querySelectorAll(".copyable");
|
||||
items.forEach(item => {
|
||||
item.title = "Click to copy";
|
||||
item.style["cursor"] = "pointer";
|
||||
item.onclick = function() {
|
||||
var range = document.createRange();
|
||||
range.selectNode(item);
|
||||
window.getSelection().addRange(range);
|
||||
document.execCommand("copy");
|
||||
window.getSelection().removeRange(range);
|
||||
console.log("Copied to clipboard");
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
.fabric {
|
||||
font: 400 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
color: #111;
|
||||
background-color: #fdfdfd;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-font-feature-settings: "kern" 1;
|
||||
-moz-font-feature-settings: "kern" 1;
|
||||
-o-font-feature-settings: "kern" 1;
|
||||
font-feature-settings: "kern" 1;
|
||||
font-kerning: normal;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.fabric table {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
color: #3f3f3f;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.fabric table tr:nth-child(even) {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.fabric table th, table td {
|
||||
padding: 1px 10px;
|
||||
}
|
||||
|
||||
.fabric table th {
|
||||
background-color: #f0f0f0;
|
||||
border: 1px solid #dedede;
|
||||
border-bottom-color: #c9c9c9;
|
||||
}
|
||||
|
||||
.fabric table td {
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<script src="{@docRoot}/copy_on_click.js"></script>
|
Loading…
Reference in New Issue