From 945d79521ecfd38e46cb11bbbf88a4f66c16d57b Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Thu, 31 May 2018 10:12:51 +0200 Subject: [PATCH 01/76] Change development version to 1.0-beta-9-SNAPSHOT --- core/pom.xml | 2 +- docs/examples/pom.xml | 2 +- gwt2/pom.xml | 2 +- pom.xml | 2 +- processors/pom.xml | 2 +- tests/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 9bdec9a7..94936b1e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -7,7 +7,7 @@ com.axellience vue-gwt-parent - 1.0-beta-8 + 1.0-beta-9-SNAPSHOT vue-gwt diff --git a/docs/examples/pom.xml b/docs/examples/pom.xml index 8fc6d00d..ee68dd0f 100644 --- a/docs/examples/pom.xml +++ b/docs/examples/pom.xml @@ -8,7 +8,7 @@ com.axellience vue-gwt-examples war - 1.0-beta-8 + 1.0-beta-9-SNAPSHOT Vue GWT Examples diff --git a/gwt2/pom.xml b/gwt2/pom.xml index 3de995b6..a2a1c489 100644 --- a/gwt2/pom.xml +++ b/gwt2/pom.xml @@ -7,7 +7,7 @@ com.axellience vue-gwt-parent - 1.0-beta-8 + 1.0-beta-9-SNAPSHOT vue-gwt-gwt2 diff --git a/pom.xml b/pom.xml index 8f253469..211e3f50 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 com.axellience vue-gwt-parent - 1.0-beta-8 + 1.0-beta-9-SNAPSHOT pom Vue GWT Parent diff --git a/processors/pom.xml b/processors/pom.xml index d2cd7aa8..4cd42196 100644 --- a/processors/pom.xml +++ b/processors/pom.xml @@ -7,7 +7,7 @@ com.axellience vue-gwt-parent - 1.0-beta-8 + 1.0-beta-9-SNAPSHOT vue-gwt-processors diff --git a/tests/pom.xml b/tests/pom.xml index bfd66936..0763366d 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -7,7 +7,7 @@ com.axellience vue-gwt-parent - 1.0-beta-8 + 1.0-beta-9-SNAPSHOT 4.0.0 From 7e76f6cbbd52e7f67823a2c7a43aeb24fd252b77 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Thu, 7 Jun 2018 19:17:44 +0200 Subject: [PATCH 02/76] feat: validator for collections in components data fields This validator looks for collection fields that don't have the @JsProperty annotation or use specific Collection types that cannot be observed with GWT2 compiler optimizations. --- pom.xml | 56 ++++++- processors/pom.xml | 37 ++++- .../ComponentExposedTypeGenerator.java | 56 ++++--- .../validators/DataFieldsValidator.java | 144 ++++++++++++++++++ .../validators/DataFieldsValidatorTest.java | 90 +++++++++++ .../test/resources/common/SimpleObject.java | 5 + ...oreModelWithListNoAnnotationComponent.java | 14 ++ .../ModelWithIgnoredTypesComponent.java | 12 ++ ...WithLinkedListWithAnnotationComponent.java | 12 ++ .../ModelWithListNoAnnotationComponent.java | 12 ++ .../ModelWithMapNoAnnotationComponent.java | 12 ++ .../ModelWithSetNoAnnotationComponent.java | 12 ++ .../ModelWithTypeParametersComponent.java | 13 ++ .../models/ModelWithIgnoredTypes.java | 13 ++ .../ModelWithLinkedListWithAnnotation.java | 10 ++ .../models/ModelWithListNoAnnotation.java | 8 + .../models/ModelWithMapNoAnnotation.java | 8 + .../models/ModelWithSetNoAnnotation.java | 8 + .../models/ModelWithTypeParameters.java | 9 ++ 19 files changed, 501 insertions(+), 30 deletions(-) create mode 100644 processors/src/main/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidator.java create mode 100644 processors/src/test/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidatorTest.java create mode 100644 processors/src/test/resources/common/SimpleObject.java create mode 100644 processors/src/test/resources/validators/IgnoreModelWithListNoAnnotationComponent.java create mode 100644 processors/src/test/resources/validators/ModelWithIgnoredTypesComponent.java create mode 100644 processors/src/test/resources/validators/ModelWithLinkedListWithAnnotationComponent.java create mode 100644 processors/src/test/resources/validators/ModelWithListNoAnnotationComponent.java create mode 100644 processors/src/test/resources/validators/ModelWithMapNoAnnotationComponent.java create mode 100644 processors/src/test/resources/validators/ModelWithSetNoAnnotationComponent.java create mode 100644 processors/src/test/resources/validators/ModelWithTypeParametersComponent.java create mode 100644 processors/src/test/resources/validators/models/ModelWithIgnoredTypes.java create mode 100644 processors/src/test/resources/validators/models/ModelWithLinkedListWithAnnotation.java create mode 100644 processors/src/test/resources/validators/models/ModelWithListNoAnnotation.java create mode 100644 processors/src/test/resources/validators/models/ModelWithMapNoAnnotation.java create mode 100644 processors/src/test/resources/validators/models/ModelWithSetNoAnnotation.java create mode 100644 processors/src/test/resources/validators/models/ModelWithTypeParameters.java diff --git a/pom.xml b/pom.xml index 211e3f50..675c65f8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,8 @@ + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 com.axellience @@ -61,6 +61,12 @@ 1.0-rc4 6.1.0 + 5.1.0 + 1.1.0 + 1.0.0 + 0.15 + 2.19 + 1.8 1.8 @@ -148,6 +154,33 @@ ${ph-css.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + + + org.junit.platform + junit-platform-commons + ${junit-platform.version} + + + org.opentest4j + opentest4j + ${opentest4j.version} + + + com.google.testing.compile + compile-testing + ${testing-compile.version} + + @@ -171,6 +204,23 @@ ${plugin.version.gwt.maven} true + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + org.junit.platform + junit-platform-surefire-provider + ${junit-platform.version} + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + + + diff --git a/processors/pom.xml b/processors/pom.xml index 4cd42196..a8d801c8 100644 --- a/processors/pom.xml +++ b/processors/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 @@ -44,6 +44,37 @@ com.helger ph-css - + + + + org.junit.jupiter + junit-jupiter-api + test + + + com.google.testing.compile + compile-testing + test + + + org.junit.platform + junit-platform-commons + test + + + org.opentest4j + opentest4j + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + \ No newline at end of file diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java index 488e844f..d787ebf9 100644 --- a/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java @@ -1,5 +1,17 @@ package com.axellience.vuegwt.processors.component; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.getSuperComponentCount; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.getSuperComponentType; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.hasTemplate; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.isFieldVisibleInJS; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.isMethodVisibleInJS; +import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentExposedTypeName; +import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentFactoryName; +import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentInjectedDependenciesName; +import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.methodToEventName; +import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasAnnotation; +import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasInterface; + import com.axellience.vuegwt.core.annotations.component.Component; import com.axellience.vuegwt.core.annotations.component.Computed; import com.axellience.vuegwt.core.annotations.component.Emit; @@ -20,6 +32,7 @@ import com.axellience.vuegwt.core.client.vnode.builder.VNodeBuilder; import com.axellience.vuegwt.core.client.vue.VueJsConstructor; import com.axellience.vuegwt.processors.component.template.ComponentTemplateProcessor; +import com.axellience.vuegwt.processors.component.validators.DataFieldsValidator; import com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil; import com.axellience.vuegwt.processors.utils.GeneratorsUtil; import com.squareup.javapoet.AnnotationSpec; @@ -30,9 +43,14 @@ import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec.Builder; import elemental2.core.JsArray; -import jsinterop.annotations.JsMethod; -import jsinterop.annotations.JsType; - +import java.lang.annotation.Annotation; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.Generated; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; @@ -40,27 +58,14 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.tools.Diagnostic.Kind; -import java.lang.annotation.Annotation; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.*; -import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentExposedTypeName; -import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentFactoryName; -import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentInjectedDependenciesName; -import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.methodToEventName; -import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasAnnotation; -import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasInterface; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsType; /** * Generate a ExposedType wrapper for the user Java {@link IsVueComponent}. @@ -77,6 +82,7 @@ public class ComponentExposedTypeGenerator private final Messager messager; private final Elements elements; private final ComponentTemplateProcessor componentTemplateProcessor; + private final DataFieldsValidator dataFieldsValidator; public ComponentExposedTypeGenerator(ProcessingEnvironment processingEnvironment) { @@ -85,6 +91,7 @@ public ComponentExposedTypeGenerator(ProcessingEnvironment processingEnvironment messager = processingEnvironment.getMessager(); elements = processingEnvironment.getElementUtils(); componentTemplateProcessor = new ComponentTemplateProcessor(processingEnvironment); + dataFieldsValidator = new DataFieldsValidator(processingEnvironment.getTypeUtils(), elements, messager); } public void generate(TypeElement component, @@ -229,21 +236,22 @@ private void processData(TypeElement component, MethodSpec.Builder optionsBuilde { Component annotation = component.getAnnotation(Component.class); - List fieldsName = ElementFilter + List dataFields = ElementFilter .fieldsIn(component.getEnclosedElements()) .stream() .filter(ComponentGeneratorsUtil::isFieldVisibleInJS) .filter(field -> field.getAnnotation(Prop.class) == null) - .map(field -> field.getSimpleName().toString()) .collect(Collectors.toList()); - if (fieldsName.isEmpty()) + if (dataFields.isEmpty()) return; + dataFields.forEach(dataFieldsValidator::validateComponentDataField); + // Declare data fields - String fieldNamesParameters = fieldsName + String fieldNamesParameters = dataFields .stream() - .map(fieldName -> "\"" + fieldName + "\"") + .map(field -> "\"" + field.getSimpleName() + "\"") .collect(Collectors.joining(", ")); optionsBuilder.addStatement("options.initData($L, $L)", diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidator.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidator.java new file mode 100644 index 00000000..18d8fc04 --- /dev/null +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidator.java @@ -0,0 +1,144 @@ +package com.axellience.vuegwt.processors.component.validators; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.processing.Messager; +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; +import javax.tools.Diagnostic.Kind; +import jsinterop.annotations.JsProperty; + +public class DataFieldsValidator { + + private final Types types; + private final TypeMirror setType; + private final TypeMirror listType; + private final TypeMirror mapType; + private final Messager messager; + + public DataFieldsValidator(Types types, Elements elements, Messager messager) { + this.types = types; + setType = types.erasure(elements.getTypeElement(Set.class.getCanonicalName()).asType()); + listType = types.erasure(elements.getTypeElement(List.class.getCanonicalName()).asType()); + mapType = types.erasure(elements.getTypeElement(Map.class.getCanonicalName()).asType()); + this.messager = messager; + } + + public void validateComponentDataField(VariableElement dataField) { + validateField(dataField, new HashSet<>(), dataField.getEnclosingElement(), + dataField.getSimpleName().toString()); + } + + private void validateField(VariableElement field, Set exploredTypes, Element component, + String debugPath) { + TypeMirror fieldType = field.asType(); + + if (hasSuppressWarning(field)) { + return; + } + + if (isCollectionField(field)) { + validateCollectionField(field, component, debugPath); + } + + validateType(fieldType, exploredTypes, component, debugPath); + } + + private void validateType(TypeMirror type, Set exploredTypes, Element component, + String debugPath) { + if (type.getKind() != TypeKind.DECLARED) { + return; + } + + DeclaredType declaredType = (DeclaredType) type; + + String fieldTypeQualifiedName = type.toString(); + if (exploredTypes.contains(fieldTypeQualifiedName)) { + return; + } + exploredTypes.add(fieldTypeQualifiedName); + + if (isJavaBaseType(type)) { + return; + } + + declaredType.getTypeArguments() + .forEach(typeArgument -> validateType(typeArgument, exploredTypes, component, + debugPath + " -> " + typeArgument)); + + Element fieldTypeElement = declaredType.asElement(); + if (fieldTypeElement == null) { + return; + } + + List childrenFields = ElementFilter + .fieldsIn(fieldTypeElement.getEnclosedElements()); + for (VariableElement childField : childrenFields) { + validateField(childField, exploredTypes, component, + debugPath + " -> " + childField.getSimpleName()); + } + } + + private void validateCollectionField(VariableElement field, Element component, String debugPath) { + if (!hasJsPropertyAnnotation(field)) { + messager.printMessage(Kind.MANDATORY_WARNING, + "Collection with missing @JsProperty annotation: " + debugPath + + ", please check the Vue GWT doc for Java Collection observation, in Component " + + component, field); + } + if (!isSupportedCollectionField(field)) { + messager.printMessage(Kind.MANDATORY_WARNING, + "Specific Collection type used as Property type, you should use either Map, Set or List: " + + debugPath + + ", please check the Vue GWT doc for Java Collection observation, in Component" + + component, field); + } + } + + private boolean hasSuppressWarning(VariableElement field) { + SuppressWarnings annotation = field.getAnnotation(SuppressWarnings.class); + if (annotation == null) { + return false; + } + + for (String s : annotation.value()) { + if ("vue-gwt-collections".equals(s)) { + return true; + } + } + + return false; + } + + private boolean isJavaBaseType(TypeMirror fieldType) { + return fieldType.toString().startsWith("java.lang"); + } + + private boolean hasJsPropertyAnnotation(VariableElement field) { + return field.getAnnotation(JsProperty.class) != null; + } + + private boolean isCollectionField(VariableElement field) { + TypeMirror type = types.erasure(field.asType()); + + return types.isAssignable(type, listType) || + types.isAssignable(type, setType) || + types.isAssignable(type, mapType); + } + + private boolean isSupportedCollectionField(VariableElement field) { + TypeMirror type = types.erasure(field.asType()); + + return types.isSameType(type, listType) || + types.isSameType(type, setType) || + types.isSameType(type, mapType); + } +} diff --git a/processors/src/test/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidatorTest.java b/processors/src/test/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidatorTest.java new file mode 100644 index 00000000..bc4cb720 --- /dev/null +++ b/processors/src/test/java/com/axellience/vuegwt/processors/component/validators/DataFieldsValidatorTest.java @@ -0,0 +1,90 @@ +package com.axellience.vuegwt.processors.component.validators; + +import static com.google.testing.compile.CompilationSubject.assertThat; +import static com.google.testing.compile.Compiler.javac; + +import com.axellience.vuegwt.processors.VueGwtProcessor; +import com.google.testing.compile.Compilation; +import com.google.testing.compile.JavaFileObjects; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class DataFieldsValidatorTest { + + @Test + @DisplayName("should throw a warning when List missing @JsProperty in the data model") + void modelWithListNoAnnotation() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/ModelWithListNoAnnotationComponent.java")); + + assertThat(compilation).hadWarningContaining("Collection with missing @JsProperty"); + } + + @Test + @DisplayName("should throw a warning when Set missing @JsProperty in the data model") + void modelWithSetNoAnnotation() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/ModelWithSetNoAnnotationComponent.java")); + + assertThat(compilation).hadWarningContaining("Collection with missing @JsProperty"); + } + + @Test + @DisplayName("should throw a warning when Map missing @JsProperty in the data model") + void modelWithMapNoAnnotation() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/ModelWithMapNoAnnotationComponent.java")); + + assertThat(compilation).hadWarningContaining("Collection with missing @JsProperty"); + } + + @Test + @DisplayName("should throw a warning when using specific List implementation in the data model, even with @JsProperty Annotation") + void modelWithLinkedListWithAnnotation() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/ModelWithLinkedListWithAnnotationComponent.java")); + + assertThat(compilation).hadWarningContaining("Specific Collection type used as Property type, you should use either Map, Set or List"); + } + + @Test + @DisplayName("should not throw a warning on Java Lang types") + void modelWithIgnoredTypes() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/ModelWithIgnoredTypesComponent.java")); + + assertThat(compilation).hadWarningCount(1); + } + + @Test + @DisplayName("should validate type parameters fields") + void modelWithTypeParameters() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/ModelWithTypeParametersComponent.java")); + + assertThat(compilation).hadWarningContaining("Collection with missing @JsProperty"); + System.out.println(compilation.errors()); + } + @Test + @DisplayName("should not throw a warning when using @SuppressWarnings") + void ignoreListWithNoAnnotation() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("validators/IgnoreModelWithListNoAnnotationComponent.java")); + + assertThat(compilation).hadWarningCount(1); + } +} \ No newline at end of file diff --git a/processors/src/test/resources/common/SimpleObject.java b/processors/src/test/resources/common/SimpleObject.java new file mode 100644 index 00000000..53919b42 --- /dev/null +++ b/processors/src/test/resources/common/SimpleObject.java @@ -0,0 +1,5 @@ +package common; + +public class SimpleObject { + String text; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/IgnoreModelWithListNoAnnotationComponent.java b/processors/src/test/resources/validators/IgnoreModelWithListNoAnnotationComponent.java new file mode 100644 index 00000000..6d867285 --- /dev/null +++ b/processors/src/test/resources/validators/IgnoreModelWithListNoAnnotationComponent.java @@ -0,0 +1,14 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithListNoAnnotation; + +@Component(hasTemplate = false) +public class IgnoreModelWithListNoAnnotationComponent implements IsVueComponent { + + @JsProperty + @SuppressWarnings("vue-gwt-collections") + ModelWithListNoAnnotation modelWithListNoAnnotation; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/ModelWithIgnoredTypesComponent.java b/processors/src/test/resources/validators/ModelWithIgnoredTypesComponent.java new file mode 100644 index 00000000..38d17ffe --- /dev/null +++ b/processors/src/test/resources/validators/ModelWithIgnoredTypesComponent.java @@ -0,0 +1,12 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithIgnoredTypes; + +@Component(hasTemplate = false) +public class ModelWithIgnoredTypesComponent implements IsVueComponent { + @JsProperty + ModelWithIgnoredTypes modelWithIgnoredTypes; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/ModelWithLinkedListWithAnnotationComponent.java b/processors/src/test/resources/validators/ModelWithLinkedListWithAnnotationComponent.java new file mode 100644 index 00000000..08455c5d --- /dev/null +++ b/processors/src/test/resources/validators/ModelWithLinkedListWithAnnotationComponent.java @@ -0,0 +1,12 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithLinkedListWithAnnotation; + +@Component(hasTemplate = false) +public class ModelWithLinkedListWithAnnotationComponent implements IsVueComponent { + @JsProperty + ModelWithLinkedListWithAnnotation modelWithLinkedListWithAnnotation; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/ModelWithListNoAnnotationComponent.java b/processors/src/test/resources/validators/ModelWithListNoAnnotationComponent.java new file mode 100644 index 00000000..ae10c40b --- /dev/null +++ b/processors/src/test/resources/validators/ModelWithListNoAnnotationComponent.java @@ -0,0 +1,12 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithListNoAnnotation; + +@Component(hasTemplate = false) +public class ModelWithListNoAnnotationComponent implements IsVueComponent { + @JsProperty + ModelWithListNoAnnotation modelWithListNoAnnotation; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/ModelWithMapNoAnnotationComponent.java b/processors/src/test/resources/validators/ModelWithMapNoAnnotationComponent.java new file mode 100644 index 00000000..fa009a81 --- /dev/null +++ b/processors/src/test/resources/validators/ModelWithMapNoAnnotationComponent.java @@ -0,0 +1,12 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithMapNoAnnotation; + +@Component(hasTemplate = false) +public class ModelWithMapNoAnnotationComponent implements IsVueComponent { + @JsProperty + ModelWithMapNoAnnotation modelWithMapNoAnnotation; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/ModelWithSetNoAnnotationComponent.java b/processors/src/test/resources/validators/ModelWithSetNoAnnotationComponent.java new file mode 100644 index 00000000..b85ba7e1 --- /dev/null +++ b/processors/src/test/resources/validators/ModelWithSetNoAnnotationComponent.java @@ -0,0 +1,12 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithSetNoAnnotation; + +@Component(hasTemplate = false) +public class ModelWithSetNoAnnotationComponent implements IsVueComponent { + @JsProperty + ModelWithSetNoAnnotation modelWithSetNoAnnotation; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/ModelWithTypeParametersComponent.java b/processors/src/test/resources/validators/ModelWithTypeParametersComponent.java new file mode 100644 index 00000000..23bb34cc --- /dev/null +++ b/processors/src/test/resources/validators/ModelWithTypeParametersComponent.java @@ -0,0 +1,13 @@ +package validators; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import jsinterop.annotations.JsProperty; +import validators.models.ModelWithTypeParameters; + +@Component(hasTemplate = false) +public class ModelWithTypeParametersComponent implements IsVueComponent { + + @JsProperty + ModelWithTypeParameters modelWithTypeParameters; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/models/ModelWithIgnoredTypes.java b/processors/src/test/resources/validators/models/ModelWithIgnoredTypes.java new file mode 100644 index 00000000..a358b208 --- /dev/null +++ b/processors/src/test/resources/validators/models/ModelWithIgnoredTypes.java @@ -0,0 +1,13 @@ +package validators.models; + +public class ModelWithIgnoredTypes { + + Class ignoredClass; + Byte byteObjectData; + Short shortObjectData; + Integer integerData; + Long longObjectData; + Float floatObjectData; + Double doubleObjectData; + Character characterData; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/models/ModelWithLinkedListWithAnnotation.java b/processors/src/test/resources/validators/models/ModelWithLinkedListWithAnnotation.java new file mode 100644 index 00000000..c2a92f3b --- /dev/null +++ b/processors/src/test/resources/validators/models/ModelWithLinkedListWithAnnotation.java @@ -0,0 +1,10 @@ +package validators.models; + +import common.SimpleObject; +import java.util.LinkedList; +import jsinterop.annotations.JsProperty; + +public class ModelWithLinkedListWithAnnotation { + @JsProperty + LinkedList list; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/models/ModelWithListNoAnnotation.java b/processors/src/test/resources/validators/models/ModelWithListNoAnnotation.java new file mode 100644 index 00000000..87c786f5 --- /dev/null +++ b/processors/src/test/resources/validators/models/ModelWithListNoAnnotation.java @@ -0,0 +1,8 @@ +package validators.models; + +import common.SimpleObject; +import java.util.List; + +public class ModelWithListNoAnnotation { + List list; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/models/ModelWithMapNoAnnotation.java b/processors/src/test/resources/validators/models/ModelWithMapNoAnnotation.java new file mode 100644 index 00000000..e44cf956 --- /dev/null +++ b/processors/src/test/resources/validators/models/ModelWithMapNoAnnotation.java @@ -0,0 +1,8 @@ +package validators.models; + +import common.SimpleObject; +import java.util.Map; + +public class ModelWithMapNoAnnotation { + Map map; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/models/ModelWithSetNoAnnotation.java b/processors/src/test/resources/validators/models/ModelWithSetNoAnnotation.java new file mode 100644 index 00000000..27009bb8 --- /dev/null +++ b/processors/src/test/resources/validators/models/ModelWithSetNoAnnotation.java @@ -0,0 +1,8 @@ +package validators.models; + +import common.SimpleObject; +import java.util.Set; + +public class ModelWithSetNoAnnotation { + Set set; +} \ No newline at end of file diff --git a/processors/src/test/resources/validators/models/ModelWithTypeParameters.java b/processors/src/test/resources/validators/models/ModelWithTypeParameters.java new file mode 100644 index 00000000..5a4613a8 --- /dev/null +++ b/processors/src/test/resources/validators/models/ModelWithTypeParameters.java @@ -0,0 +1,9 @@ +package validators.models; + +import jsinterop.annotations.JsProperty; +import java.util.List; + +public class ModelWithTypeParameters { + @JsProperty + List modelWithListNoAnnotationList; +} \ No newline at end of file From 198d37ba387b8d1afd2968a0680a4ba7bda8d03f Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Sat, 9 Jun 2018 10:36:10 +0200 Subject: [PATCH 03/76] fix: remove line breaks on computed property test --- .../components/basic/computed/ComputedTestComponent.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/computed/ComputedTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/computed/ComputedTestComponent.html index 710fa882..3cbc3fc1 100644 --- a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/computed/ComputedTestComponent.html +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/computed/ComputedTestComponent.html @@ -1,3 +1 @@ -
- {{ computedProperty }} -
\ No newline at end of file +
{{ computedProperty }}
\ No newline at end of file From 22294001146b9d86669be36515a9dfebe88e5728 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Sat, 9 Jun 2018 11:11:52 +0200 Subject: [PATCH 04/76] tests: make component template processor also look in CLASS_PATH This is needed for templates to be found when using google compile testing. --- .../template/ComponentTemplateProcessor.java | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java index c24577f4..4c563d67 100644 --- a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java @@ -1,5 +1,11 @@ package com.axellience.vuegwt.processors.component.template; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.getComponentLocalComponents; +import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.getSuperComponentType; +import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentToTagName; +import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.getComputedPropertyName; +import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasAnnotation; + import com.axellience.vuegwt.core.annotations.component.Component; import com.axellience.vuegwt.core.annotations.component.Computed; import com.axellience.vuegwt.core.annotations.component.JsComponent; @@ -18,7 +24,10 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec.Builder; - +import java.io.IOException; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; @@ -32,16 +41,6 @@ import javax.tools.Diagnostic.Kind; import javax.tools.FileObject; import javax.tools.StandardLocation; -import java.io.IOException; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.getComponentLocalComponents; -import static com.axellience.vuegwt.processors.utils.ComponentGeneratorsUtil.getSuperComponentType; -import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.componentToTagName; -import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.getComputedPropertyName; -import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasAnnotation; /** * Process the HTML template for a given {@link IsVueComponent}. @@ -227,18 +226,31 @@ private Optional getTemplateContent(ClassName componentTypeName, TypeElement componentTypeElement) { String path = slashify(componentTypeName.reflectionName()) + ".html"; + Optional result = getTemplateContentAtLocation(path, StandardLocation.CLASS_OUTPUT); + if (result.isPresent()) + return result; + + result = getTemplateContentAtLocation(path, StandardLocation.CLASS_PATH); + if (result.isPresent()) + return result; + + messager.printMessage(Kind.ERROR, + "Couldn't find template for component: " + + componentTypeName.simpleName() + + ". Make sure you included src/main/java in your Resources. Check our setup guide for help.", + componentTypeElement); + return Optional.empty(); + } + + private Optional getTemplateContentAtLocation(String path, StandardLocation location) + { FileObject resource; try { - resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", path); + resource = filer.getResource(location, "", path); } - catch (IOException e) + catch (IOException ignore) { - messager.printMessage(Kind.ERROR, - "Couldn't find template for component: " - + componentTypeName.simpleName() - + ". Make sure you included src/main/java in your Resources. Check our setup guide for help.", - componentTypeElement); return Optional.empty(); } @@ -249,11 +261,6 @@ private Optional getTemplateContent(ClassName componentTypeName, } catch (IOException e) { - messager.printMessage(Kind.ERROR, - "Failed to open template file for component: " - + componentTypeName.simpleName() - + ". Make sure you included src/main/java in your Resources. Check our setup guide for help.", - componentTypeElement); return Optional.empty(); } } From f699a56dbe22850bb0a2d3705bfc581d93bf5198 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Sat, 9 Jun 2018 11:21:38 +0200 Subject: [PATCH 05/76] tests: remove date from @Generated annotation This prevented source comparison in tests as the value was always different at each build. --- .../processors/component/ComponentExposedTypeGenerator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java index d787ebf9..2c0395bd 100644 --- a/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/ComponentExposedTypeGenerator.java @@ -44,7 +44,6 @@ import com.squareup.javapoet.TypeSpec.Builder; import elemental2.core.JsArray; import java.lang.annotation.Annotation; -import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map.Entry; @@ -163,7 +162,6 @@ private Builder getComponentExposedTypeBuilder(TypeElement component, ClassName .addAnnotation(AnnotationSpec .builder(Generated.class) .addMember("value", "$S", ComponentExposedTypeGenerator.class.getCanonicalName()) - .addMember("date", "$S", new Date().toString()) .addMember("comments", "$S", "https://github.com/Axellience/vue-gwt") .build()); From f4d65b00d0af52c33a5d32bdb6b1e44ccd08c01b Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Sat, 9 Jun 2018 11:49:21 +0200 Subject: [PATCH 06/76] fix: remove line breaks on prop default value test --- .../basic/propdefault/PropDefaultTestComponent.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/propdefault/PropDefaultTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/propdefault/PropDefaultTestComponent.html index d2556fc6..3e610d52 100644 --- a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/propdefault/PropDefaultTestComponent.html +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/propdefault/PropDefaultTestComponent.html @@ -1,3 +1 @@ -
- {{ optionalProp }} -
\ No newline at end of file +
{{ optionalProp }}
\ No newline at end of file From 20f331c7e1ffcf1cfcaaa2e9a71a1e686ee26ff0 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Sat, 9 Jun 2018 11:56:00 +0200 Subject: [PATCH 07/76] fix: template expressions with line breaks on windows Template expressions ({{ }}) with line breaks were not parsed correctly on windows. Fix #38 --- .../template/parser/TemplateParser.java | 33 +++++++++---------- .../template/parser/TemplateParserTest.java | 24 ++++++++++++++ .../test/resources/common/SimpleObject.java | 4 +++ .../MustacheExpressionComponent.html | 6 ++++ .../MustacheExpressionComponent.java | 12 +++++++ ...ustacheExpressionComponentExposedType.java | 18 ++++++++++ .../basic/data/DataTestComponent.html | 4 +-- 7 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 processors/src/test/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParserTest.java create mode 100644 processors/src/test/resources/templateparser/MustacheExpressionComponent.html create mode 100644 processors/src/test/resources/templateparser/MustacheExpressionComponent.java create mode 100644 processors/src/test/resources/templateparser/compileresult/MustacheExpressionComponentExposedType.java diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java index b4727f55..5ccb0de0 100644 --- a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java @@ -1,5 +1,8 @@ package com.axellience.vuegwt.processors.component.template.parser; +import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.propNameToAttributeName; +import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.stringTypeToTypeName; + import com.axellience.vuegwt.core.annotations.component.Prop; import com.axellience.vuegwt.processors.component.template.parser.TemplateScopedCssParser.ScopedCssResult; import com.axellience.vuegwt.processors.component.template.parser.context.TemplateParserContext; @@ -20,18 +23,6 @@ import com.github.javaparser.ast.nodeTypes.NodeWithType; import com.github.javaparser.ast.type.Type; import com.squareup.javapoet.TypeName; -import jsinterop.base.Any; -import net.htmlparser.jericho.Attribute; -import net.htmlparser.jericho.Attributes; -import net.htmlparser.jericho.CharacterReference; -import net.htmlparser.jericho.Config; -import net.htmlparser.jericho.Element; -import net.htmlparser.jericho.OutputDocument; -import net.htmlparser.jericho.Segment; -import net.htmlparser.jericho.Source; -import net.htmlparser.jericho.Tag; - -import javax.annotation.processing.Messager; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -43,9 +34,17 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; - -import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.propNameToAttributeName; -import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.stringTypeToTypeName; +import javax.annotation.processing.Messager; +import jsinterop.base.Any; +import net.htmlparser.jericho.Attribute; +import net.htmlparser.jericho.Attributes; +import net.htmlparser.jericho.CharacterReference; +import net.htmlparser.jericho.Config; +import net.htmlparser.jericho.Element; +import net.htmlparser.jericho.OutputDocument; +import net.htmlparser.jericho.Segment; +import net.htmlparser.jericho.Source; +import net.htmlparser.jericho.Tag; /** * Parse an HTML Vue GWT template. @@ -59,7 +58,7 @@ public class TemplateParser { private static Pattern VUE_ATTR_PATTERN = Pattern.compile("^(v-|:|@).*"); - private static Pattern VUE_MUSTACHE_PATTERN = Pattern.compile("\\{\\{.*?}}"); + private static Pattern VUE_MUSTACHE_PATTERN = Pattern.compile("\\{\\{.*?}}", Pattern.DOTALL); private TemplateParserContext context; private Messager messager; @@ -233,7 +232,7 @@ private void processTextNode(Segment textSegment) int start = matcher.start(); int end = matcher.end(); if (start > 0) - newText.append(elementText.substring(lastEnd, start)); + newText.append(elementText, lastEnd, start); currentExpressionReturnType = TypeName.get(String.class); String expressionString = elementText.substring(start + 2, end - 2).trim(); diff --git a/processors/src/test/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParserTest.java b/processors/src/test/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParserTest.java new file mode 100644 index 00000000..dc939b45 --- /dev/null +++ b/processors/src/test/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParserTest.java @@ -0,0 +1,24 @@ +package com.axellience.vuegwt.processors.component.template.parser; + +import static com.google.testing.compile.CompilationSubject.assertThat; +import static com.google.testing.compile.Compiler.javac; + +import com.axellience.vuegwt.processors.VueGwtProcessor; +import com.google.testing.compile.Compilation; +import com.google.testing.compile.JavaFileObjects; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TemplateParserTest { + @Test + @DisplayName("should compile a template expression with linebreaks inside") + void modelWithListNoAnnotation() { + Compilation compilation = + javac() + .withProcessors(new VueGwtProcessor()) + .compile(JavaFileObjects.forResource("templateparser/MustacheExpressionComponent.java")); + + assertThat(compilation).generatedSourceFile("templateparser.MustacheExpressionComponentExposedType") + .containsElementsIn(JavaFileObjects.forResource("templateparser/compileresult/MustacheExpressionComponentExposedType.java")); + } +} \ No newline at end of file diff --git a/processors/src/test/resources/common/SimpleObject.java b/processors/src/test/resources/common/SimpleObject.java index 53919b42..055ab57b 100644 --- a/processors/src/test/resources/common/SimpleObject.java +++ b/processors/src/test/resources/common/SimpleObject.java @@ -2,4 +2,8 @@ public class SimpleObject { String text; + + public String getText() { + return text; + } } \ No newline at end of file diff --git a/processors/src/test/resources/templateparser/MustacheExpressionComponent.html b/processors/src/test/resources/templateparser/MustacheExpressionComponent.html new file mode 100644 index 00000000..edd3ed8b --- /dev/null +++ b/processors/src/test/resources/templateparser/MustacheExpressionComponent.html @@ -0,0 +1,6 @@ +
{{ + + simpleObject + .getText() + }} +
\ No newline at end of file diff --git a/processors/src/test/resources/templateparser/MustacheExpressionComponent.java b/processors/src/test/resources/templateparser/MustacheExpressionComponent.java new file mode 100644 index 00000000..7013074d --- /dev/null +++ b/processors/src/test/resources/templateparser/MustacheExpressionComponent.java @@ -0,0 +1,12 @@ +package templateparser; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import common.SimpleObject; +import jsinterop.annotations.JsProperty; + +@Component +public class MustacheExpressionComponent implements IsVueComponent { + @JsProperty + SimpleObject simpleObject; +} \ No newline at end of file diff --git a/processors/src/test/resources/templateparser/compileresult/MustacheExpressionComponentExposedType.java b/processors/src/test/resources/templateparser/compileresult/MustacheExpressionComponentExposedType.java new file mode 100644 index 00000000..355f1a2d --- /dev/null +++ b/processors/src/test/resources/templateparser/compileresult/MustacheExpressionComponentExposedType.java @@ -0,0 +1,18 @@ +package templateparser; + +@Generated( + value = "com.axellience.vuegwt.processors.component.ComponentExposedTypeGenerator", + comments = "https://github.com/Axellience/vue-gwt" +) +@JsType( + namespace = "VueGWTExposedTypesRepository", + name = "templateparser_MustacheExpressionComponent" +) +public class MustacheExpressionComponentExposedType extends MustacheExpressionComponent { + @JsMethod + @SuppressWarnings("unusable-by-js") + public String exp$0() { + // MustacheExpressionComponent.html, line 1 + return VueGWTTools.templateExpressionToString(simpleObject.getText()); + } +} \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html index 6ceee7ce..2ff73819 100644 --- a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html @@ -23,9 +23,7 @@
  • {{ doubleObjectData }}
  • {{ characterData }}
  • {{ stringData }}
  • -
  • - {{ simpleObjectData == null ? "" : simpleObjectData.getStringProperty() }} -
  • +
  • {{ simpleObjectData == null ? "" : simpleObjectData.getStringProperty() }}
  • From d8d4292dc0cefe032b51baa9e80146fbf972a247 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Mon, 11 Jun 2018 23:06:23 +0200 Subject: [PATCH 08/76] tests: fix test on data with line breaks not passing on Windows --- .../tests/client/components/basic/data/DataTestComponent.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html index 2ff73819..6c425236 100644 --- a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/data/DataTestComponent.html @@ -35,7 +35,6 @@ dataWithLineBreaks .getStringProperty() - }} - +}} From 16898f12f0845c955244d0d8146a92753b563ac9 Mon Sep 17 00:00:00 2001 From: Slava P Date: Tue, 12 Jun 2018 22:07:10 -0700 Subject: [PATCH 09/76] feat: add scoped SASS/SCSS support in templates * SCSS support added. * tests for scoped SCSS styling added. * Pair replaced with TemplateFileResource. Fix #40 --- pom.xml | 8 ++- processors/pom.xml | 4 ++ .../template/ComponentTemplateProcessor.java | 64 +++++++++++-------- .../template/parser/TemplateParser.java | 62 +++++++++++++----- .../style/scoped/ScopedTestComponent.html | 31 +++++++++ .../style/scoped/ScopedTestComponent.java | 24 +++++++ .../style/scoped/ScopedTestComponent.scss | 15 +++++ .../components/style/scoped.spec.js | 40 ++++++++++++ 8 files changed, 205 insertions(+), 43 deletions(-) create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.html create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.java create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.scss create mode 100644 tests/src/test/javascript/components/style/scoped.spec.js diff --git a/pom.xml b/pom.xml index 675c65f8..dca61f41 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,8 @@ 3.4 3.0.1 1.0-rc4 - 6.1.0 + 6.1.1 + 5.7.3 5.1.0 1.1.0 @@ -153,6 +154,11 @@ ph-css ${ph-css.version} + + io.bit3 + jsass + ${jsass.version} + diff --git a/processors/pom.xml b/processors/pom.xml index a8d801c8..3f6e56c2 100644 --- a/processors/pom.xml +++ b/processors/pom.xml @@ -44,6 +44,10 @@ com.helger ph-css + + io.bit3 + jsass + diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java index 4c563d67..d9b6e31a 100644 --- a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/ComponentTemplateProcessor.java @@ -6,6 +6,26 @@ import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.getComputedPropertyName; import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.hasAnnotation; +import java.io.IOException; +import java.net.URI; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import javax.annotation.processing.Filer; +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + import com.axellience.vuegwt.core.annotations.component.Component; import com.axellience.vuegwt.core.annotations.component.Computed; import com.axellience.vuegwt.core.annotations.component.JsComponent; @@ -24,23 +44,6 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec.Builder; -import java.io.IOException; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import javax.annotation.processing.Filer; -import javax.annotation.processing.Messager; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; -import javax.lang.model.util.Elements; -import javax.tools.Diagnostic.Kind; -import javax.tools.FileObject; -import javax.tools.StandardLocation; /** * Process the HTML template for a given {@link IsVueComponent}. @@ -63,7 +66,7 @@ public void processComponentTemplate(TypeElement componentTypeElement, Builder componentExposedTypeBuilder) { ClassName componentTypeName = ClassName.get(componentTypeElement); - Optional optionalTemplateContent = + Optional optionalTemplateContent = getTemplateContent(componentTypeName, componentTypeElement); if (!optionalTemplateContent.isPresent()) @@ -82,9 +85,10 @@ public void processComponentTemplate(TypeElement componentTypeElement, // Parse the template TemplateParserResult templateParserResult = new TemplateParser().parseHtmlTemplate( - optionalTemplateContent.get(), + optionalTemplateContent.get().content, templateParserContext, - messager); + messager, + optionalTemplateContent.get().uri); registerScopedCss(componentExposedTypeBuilder, templateParserResult); @@ -222,11 +226,21 @@ private void processLocalComponentClass(LocalComponents localComponents, }); } - private Optional getTemplateContent(ClassName componentTypeName, + private static class TemplateFileResource { + public final String content; + public final URI uri; + + public TemplateFileResource(String content, URI uri) { + this.content = content; + this.uri = uri; + } + } + + private Optional getTemplateContent(ClassName componentTypeName, TypeElement componentTypeElement) { String path = slashify(componentTypeName.reflectionName()) + ".html"; - Optional result = getTemplateContentAtLocation(path, StandardLocation.CLASS_OUTPUT); + Optional result = getTemplateContentAtLocation(path, StandardLocation.CLASS_OUTPUT); if (result.isPresent()) return result; @@ -242,7 +256,7 @@ private Optional getTemplateContent(ClassName componentTypeName, return Optional.empty(); } - private Optional getTemplateContentAtLocation(String path, StandardLocation location) + private Optional getTemplateContentAtLocation(String path, StandardLocation location) { FileObject resource; try @@ -257,7 +271,7 @@ private Optional getTemplateContentAtLocation(String path, StandardLocat // Get template content from HTML file try { - return Optional.of(resource.getCharContent(true).toString()); + return Optional.of(new TemplateFileResource(resource.getCharContent(true).toString(), resource.toUri())); } catch (IOException e) { @@ -265,7 +279,7 @@ private Optional getTemplateContentAtLocation(String path, StandardLocat } } - private void registerScopedCss(Builder componentExposedTypeBuilder, + private static void registerScopedCss(Builder componentExposedTypeBuilder, TemplateParserResult templateParserResult) { String scopedCss = templateParserResult.getScopedCss(); diff --git a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java index 5ccb0de0..ba4f43a9 100644 --- a/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java +++ b/processors/src/main/java/com/axellience/vuegwt/processors/component/template/parser/TemplateParser.java @@ -3,6 +3,21 @@ import static com.axellience.vuegwt.processors.utils.GeneratorsNameUtil.propNameToAttributeName; import static com.axellience.vuegwt.processors.utils.GeneratorsUtil.stringTypeToTypeName; +import java.net.URI; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import javax.annotation.processing.Messager; + import com.axellience.vuegwt.core.annotations.component.Prop; import com.axellience.vuegwt.processors.component.template.parser.TemplateScopedCssParser.ScopedCssResult; import com.axellience.vuegwt.processors.component.template.parser.context.TemplateParserContext; @@ -23,18 +38,12 @@ import com.github.javaparser.ast.nodeTypes.NodeWithType; import com.github.javaparser.ast.type.Type; import com.squareup.javapoet.TypeName; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import javax.annotation.processing.Messager; + +import io.bit3.jsass.CompilationException; +import io.bit3.jsass.Compiler; +import io.bit3.jsass.Options; +import io.bit3.jsass.Output; +import io.bit3.jsass.context.StringContext; import jsinterop.base.Any; import net.htmlparser.jericho.Attribute; import net.htmlparser.jericho.Attributes; @@ -64,6 +73,7 @@ public class TemplateParser private Messager messager; private TemplateParserLogger logger; private TemplateParserResult result; + private URI htmlTemplateUri; private Attribute currentAttribute; private LocalComponentProp currentProp; @@ -79,11 +89,12 @@ public class TemplateParser * @return A {@link TemplateParserResult} containing the processed template and expressions */ public TemplateParserResult parseHtmlTemplate(String htmlTemplate, - TemplateParserContext context, Messager messager) + TemplateParserContext context, Messager messager, URI htmlTemplateUri) { this.context = context; this.messager = messager; this.logger = new TemplateParserLogger(context, messager); + this.htmlTemplateUri = htmlTemplateUri; initJerichoConfig(this.logger); @@ -99,7 +110,7 @@ public TemplateParserResult parseHtmlTemplate(String htmlTemplate, return result; } - private void initJerichoConfig(TemplateParserLogger logger) + private static void initJerichoConfig(TemplateParserLogger logger) { // Allow as many invalid character in attributes as possible Attributes.setDefaultMaxErrorCount(Integer.MAX_VALUE); @@ -140,6 +151,10 @@ private String processScopedCss(Source doc) { .peek(styleScoped -> { String css = styleScoped.getContent().toString().trim(); if (!css.isEmpty()) { + String lang = styleScoped.getAttributeValue("lang"); + if ("scss".equalsIgnoreCase(lang)) { // lang="scss" + css = scssToCss(css); + } TemplateScopedCssParser scopedCssParser = new TemplateScopedCssParser(messager); Optional scopedCssResult = scopedCssParser.parse( context.getComponentTypeElement(), css); @@ -154,6 +169,19 @@ private String processScopedCss(Source doc) { return scopedCss[0]; } + private String scssToCss(String scss) { + Compiler compiler = new Compiler(); + Options options = new Options(); + try { + StringContext context = new StringContext(scss, this.htmlTemplateUri, null/*outputPath*/, options); + Output output = compiler.compile(context); + return output.getCss(); + } catch (CompilationException e) { + logger.error("SCSS compile failed: " + e.getErrorText()); + throw new RuntimeException(e); + } + } + /** * Recursive method that will process the whole template DOM tree. * @param element Current element being processed @@ -446,13 +474,13 @@ private boolean shouldSkipExpressionProcessing(String expressionString) expressionString); } - private boolean isAttributeBinding(Attribute attribute) + private static boolean isAttributeBinding(Attribute attribute) { String attributeName = attribute.getKey().toLowerCase(); return attributeName.startsWith(":") || attributeName.startsWith("v-bind:"); } - private boolean isEventBinding(Attribute attribute) + private static boolean isEventBinding(Attribute attribute) { String attributeName = attribute.getKey().toLowerCase(); return attributeName.startsWith("@") || attributeName.startsWith("v-on:"); @@ -571,7 +599,7 @@ private void resolveTypesUsingImports(Expression expression) { if (expression instanceof NodeWithType) { - NodeWithType nodeWithType = ((NodeWithType) expression); + NodeWithType nodeWithType = ((NodeWithType) expression); nodeWithType.setType(getQualifiedName(nodeWithType.getType())); } diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.html new file mode 100644 index 00000000..50b61160 --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.html @@ -0,0 +1,31 @@ +
    +

    +
    +

    The water would boil.

    +
    Careful!
    +
    +

    The water would not boil.

    +
    + + \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.java b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.java new file mode 100644 index 00000000..0be985ba --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.java @@ -0,0 +1,24 @@ +package com.axellience.vuegwt.tests.client.components.style.scoped; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.annotations.component.Prop; +import com.axellience.vuegwt.core.client.component.IsVueComponent; + +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsProperty; + +@Component +public class ScopedTestComponent implements IsVueComponent { + @Prop @JsProperty String celsius; + + @JsMethod double parseFloat(String value) { + if (value == null) return 0; + String s = value.trim(); + if (s.isEmpty()) return 0; + try { + return Double.parseDouble(s); + } catch (Exception e) { + return 0; + } + } +} \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.scss b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.scss new file mode 100644 index 00000000..2635d10e --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/style/scoped/ScopedTestComponent.scss @@ -0,0 +1,15 @@ +$boiling-border-color: blue; + +$attention-color: red; + +$attention-info-color: orange; + +$relax-color: green; + +$vendors: "-moz-", "-webkit-", ""; // you can add other vendor prefixes or remove them without needing to change the mixin. + +@mixin rounded($radius: 0.5em) { + @each $vendor in $vendors { + #{$vendor}border-radius: $radius; + } +} diff --git a/tests/src/test/javascript/components/style/scoped.spec.js b/tests/src/test/javascript/components/style/scoped.spec.js new file mode 100644 index 00000000..cd4c5120 --- /dev/null +++ b/tests/src/test/javascript/components/style/scoped.spec.js @@ -0,0 +1,40 @@ +import {expect} from 'chai' +import { + createAndMountComponent, destroyComponent, getElement, onGwtReady, + onNextTick +} from '../../vue-gwt-tests-utils' + +describe('Scoped styling', () => { + let component; + + beforeEach(() => onGwtReady().then(() => { + component = createAndMountComponent( + 'com.axellience.vuegwt.tests.client.components.style.scoped.ScopedTestComponent'); + })); + + afterEach(() => { + destroyComponent(component); + }); + + it('check non-boiling label has proper styling', () => { + component.celsius = '22'; + return onNextTick(() => { + const element = getElement(component, '.relax'); + expect(element).to.exist; + const c = window.getComputedStyle(element, null).getPropertyValue('color'); + expect(c).to.equal('rgb(0, 128, 0)'); // green + const b = window.getComputedStyle(element, null).getPropertyValue('border-radius'); + expect(b).to.equal('8px'); // 0.5em + }); + }); + + it('check boiling label has proper styling', () => { + component.celsius = '101'; + return onNextTick(() => { + const element = getElement(component, '.attention'); + expect(element).to.exist; + const c = window.getComputedStyle(element, null).getPropertyValue('color'); + expect(c).to.equal('rgb(255, 0, 0)'); // red + }); + }); +}); From 9e7ab7e3ac8e03f1a155fc63e051131f53d37ce7 Mon Sep 17 00:00:00 2001 From: Adrien Baron Date: Wed, 13 Jun 2018 15:07:11 +0200 Subject: [PATCH 10/76] tests: add more tests for @watch and $watch * test: make nextTick return a Promise instead of taking a callback * test: add tests for Watch and $watch, both on data and props --- .../basic/watch/WatchTestComponent.html | 3 - .../basic/watch/WatchTestComponent.java | 37 -- .../watch/data/WatchDataTestComponent.html | 1 + .../watch/data/WatchDataTestComponent.java | 154 +++++ .../prop/WatchPropParentTestComponent.html | 6 + .../prop/WatchPropParentTestComponent.java | 67 +++ .../watch/prop/WatchPropTestComponent.html | 1 + .../watch/prop/WatchPropTestComponent.java | 117 ++++ .../components/basic/computed.spec.js | 8 +- .../javascript/components/basic/data.spec.js | 47 +- .../javascript/components/basic/prop.spec.js | 9 +- .../components/basic/propdefault.spec.js | 6 +- .../components/basic/propvalidator.spec.js | 8 +- .../javascript/components/basic/watch.spec.js | 527 +++++++++++++++++- .../conditionalrendering/vif.spec.js | 27 +- .../conditionalrendering/vshow.spec.js | 9 +- .../events/types/EventTypes.spec.js | 39 +- .../components/style/classbinding.spec.js | 45 +- .../style/inlinestylebinding.spec.js | 11 +- .../test/javascript/vue-gwt-tests-utils.js | 13 +- 20 files changed, 971 insertions(+), 164 deletions(-) delete mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.html delete mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.java create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.html create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.java create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.html create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.java create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.html create mode 100644 tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.java diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.html deleted file mode 100644 index ea557dd3..00000000 --- a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.html +++ /dev/null @@ -1,3 +0,0 @@ -
    - {{ watchedData }} -
    \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.java b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.java deleted file mode 100644 index ff2d9c69..00000000 --- a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/WatchTestComponent.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.axellience.vuegwt.tests.client.components.basic.watch; - -import com.axellience.vuegwt.core.annotations.component.Component; -import com.axellience.vuegwt.core.annotations.component.Watch; -import com.axellience.vuegwt.core.client.component.IsVueComponent; -import com.axellience.vuegwt.tests.client.common.SimpleObject; -import jsinterop.annotations.JsMethod; -import jsinterop.annotations.JsProperty; - -@Component -public class WatchTestComponent implements IsVueComponent { - - @JsProperty - SimpleObject watchedData = null; - - @JsProperty - SimpleObject newValue; - - @JsProperty - SimpleObject oldValue; - - @Watch("watchedData") - public void onWatchedDataChange(SimpleObject newValue, SimpleObject oldValue) { - this.newValue = newValue; - this.oldValue = oldValue; - } - - @JsMethod - public void changeWatchedData(String property) { - if (property == null) { - watchedData = null; - } else { - watchedData = new SimpleObject(); - watchedData.setStringProperty(property); - } - } -} diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.html new file mode 100644 index 00000000..281c6866 --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.java b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.java new file mode 100644 index 00000000..f50fbf68 --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/data/WatchDataTestComponent.java @@ -0,0 +1,154 @@ +package com.axellience.vuegwt.tests.client.components.basic.watch.data; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.annotations.component.Watch; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import com.axellience.vuegwt.core.client.component.hooks.HasCreated; +import com.axellience.vuegwt.tests.client.common.SimpleObject; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsProperty; + +@Component +public class WatchDataTestComponent implements IsVueComponent, HasCreated { + + @JsProperty + SimpleObject watchedDataAnnotation = null; + + @JsProperty + SimpleObject newValueAnnotation; + + @JsProperty + SimpleObject oldValueAnnotation; + + @JsProperty + String newValueAnnotationProperty; + + @JsProperty + String oldValueAnnotationProperty; + + @JsProperty + SimpleObject watchedDataDeepAnnotation = null; + + @JsProperty + String newValueAnnotationDeep; + + @JsProperty + String oldValueAnnotationDeep; + + @JsProperty + SimpleObject watchedData$WatchString = null; + + @JsProperty + SimpleObject newValue$WatchString; + + @JsProperty + SimpleObject oldValue$WatchString; + + @JsProperty + String newValue$WatchStringProperty; + + @JsProperty + String oldValue$WatchStringProperty; + + @JsProperty + SimpleObject watchedData$WatchMethod = null; + + @JsProperty + SimpleObject newValue$WatchMethod; + + @JsProperty + SimpleObject oldValue$WatchMethod; + + @JsProperty + String newValue$WatchMethodProperty; + + @JsProperty + String oldValue$WatchMethodProperty; + + @Override + public void created() { + vue().$watch("watchedData$WatchString", (newValue, oldValue) -> { + this.newValue$WatchString = (SimpleObject) newValue; + this.oldValue$WatchString = (SimpleObject) oldValue; + }); + vue().$watch("watchedData$WatchString.stringProperty", (newValue, oldValue) -> { + this.newValue$WatchStringProperty = (String) newValue; + this.oldValue$WatchStringProperty = (String) oldValue; + }); + + vue().$watch(() -> watchedData$WatchMethod, (newValue, oldValue) -> { + this.newValue$WatchMethod = newValue; + this.oldValue$WatchMethod = oldValue; + }); + vue().$watch( + () -> { + if (watchedData$WatchMethod == null) { + return null; + } + return watchedData$WatchMethod.getStringProperty(); + }, + (newValue, oldValue) -> { + this.newValue$WatchMethodProperty = newValue; + this.oldValue$WatchMethodProperty = oldValue; + } + ); + } + + @Watch("watchedDataAnnotation") + public void onWatchedDataChange(SimpleObject newValue, SimpleObject oldValue) { + this.newValueAnnotation = newValue; + this.oldValueAnnotation = oldValue; + } + + @Watch("watchedDataAnnotation.stringProperty") + public void onWatchedDataPropertyChange(String newValue, String oldValue) { + this.newValueAnnotationProperty = newValue; + this.oldValueAnnotationProperty = oldValue; + } + + @Watch(value = "watchedDataDeepAnnotation", isDeep = true) + public void onWatchedDataDeepChange(SimpleObject newValue, SimpleObject oldValue) { + this.newValueAnnotationDeep = newValue != null ? newValue.getStringProperty() : null; + this.oldValueAnnotationDeep = oldValue != null ? oldValue.getStringProperty() : null; + } + + @JsMethod + public void changeWatchedDataAnnotation(String property) { + if (property == null) { + watchedDataAnnotation = null; + } else { + watchedDataAnnotation = new SimpleObject(); + watchedDataAnnotation.setStringProperty(property); + } + } + + @JsMethod + public void changeWatchedDataDeepAnnotation(String property) { + if (property == null) { + watchedDataDeepAnnotation = null; + } else { + watchedDataDeepAnnotation = new SimpleObject(); + watchedDataDeepAnnotation.setStringProperty(property); + } + } + + @JsMethod + public void changeWatchedData$WatchString(String property) { + if (property == null) { + watchedData$WatchString = null; + } else { + watchedData$WatchString = new SimpleObject(); + watchedData$WatchString.setStringProperty(property); + } + } + + @JsMethod + public void changeWatchedData$WatchMethod(String property) { + if (property == null) { + watchedData$WatchMethod = null; + } else { + watchedData$WatchMethod = new SimpleObject(); + watchedData$WatchMethod.setStringProperty(property); + } + } +} diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.html new file mode 100644 index 00000000..7d678cf2 --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.java b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.java new file mode 100644 index 00000000..5a415376 --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropParentTestComponent.java @@ -0,0 +1,67 @@ +package com.axellience.vuegwt.tests.client.components.basic.watch.prop; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import com.axellience.vuegwt.tests.client.common.SimpleObject; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsProperty; + +@Component(components = WatchPropTestComponent.class) +public class WatchPropParentTestComponent implements IsVueComponent { + @JsProperty + SimpleObject watchedPropAnnotation = null; + + @JsProperty + SimpleObject watchedPropDeepAnnotation = null; + + @JsProperty + SimpleObject watchedProp$WatchString = null; + + @JsProperty + SimpleObject watchedProp$WatchMethod = null; + + @JsMethod + public void changeWatchedPropAnnotation(String property) { + if (property == null) { + watchedPropAnnotation = null; + } else { + watchedPropAnnotation = new SimpleObject(); + watchedPropAnnotation.setStringProperty(property); + } + } + + @JsMethod + public void changeWatchedPropDeepAnnotation(String property) { + if (property == null) { + watchedPropDeepAnnotation = null; + } else { + watchedPropDeepAnnotation = new SimpleObject(); + watchedPropDeepAnnotation.setStringProperty(property); + } + } + + @JsMethod + public void changeWatchedProp$WatchString(String property) { + if (property == null) { + watchedProp$WatchString = null; + } else { + watchedProp$WatchString = new SimpleObject(); + watchedProp$WatchString.setStringProperty(property); + } + } + + @JsMethod + public void changeWatchedProp$WatchMethod(String property) { + if (property == null) { + watchedProp$WatchMethod = null; + } else { + watchedProp$WatchMethod = new SimpleObject(); + watchedProp$WatchMethod.setStringProperty(property); + } + } + + @JsMethod + public WatchPropTestComponent getWatchPropTestComponent() { + return vue().$ref("watchPropTest"); + } +} diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.html b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.html new file mode 100644 index 00000000..281c6866 --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.java b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.java new file mode 100644 index 00000000..5f1577ba --- /dev/null +++ b/tests/src/main/java/com/axellience/vuegwt/tests/client/components/basic/watch/prop/WatchPropTestComponent.java @@ -0,0 +1,117 @@ +package com.axellience.vuegwt.tests.client.components.basic.watch.prop; + +import com.axellience.vuegwt.core.annotations.component.Component; +import com.axellience.vuegwt.core.annotations.component.Prop; +import com.axellience.vuegwt.core.annotations.component.Watch; +import com.axellience.vuegwt.core.client.component.IsVueComponent; +import com.axellience.vuegwt.core.client.component.hooks.HasCreated; +import com.axellience.vuegwt.tests.client.common.SimpleObject; +import jsinterop.annotations.JsProperty; + +@Component +public class WatchPropTestComponent implements IsVueComponent, HasCreated { + @Prop + @JsProperty + SimpleObject watchedPropAnnotation; + + @JsProperty + SimpleObject newValueAnnotation; + + @JsProperty + SimpleObject oldValueAnnotation; + + @JsProperty + String newValueAnnotationProperty; + + @JsProperty + String oldValueAnnotationProperty; + + @Prop + @JsProperty + SimpleObject watchedPropDeepAnnotation = null; + + @JsProperty + String newValueAnnotationDeep; + + @JsProperty + String oldValueAnnotationDeep; + + @Prop + @JsProperty + SimpleObject watchedPropWatchString; + + @JsProperty + SimpleObject newValue$WatchString; + + @JsProperty + SimpleObject oldValue$WatchString; + + @JsProperty + String newValue$WatchStringProperty; + + @JsProperty + String oldValue$WatchStringProperty; + + @Prop + @JsProperty + SimpleObject watchedPropWatchMethod; + + @JsProperty + SimpleObject newValue$WatchMethod; + + @JsProperty + SimpleObject oldValue$WatchMethod; + + @JsProperty + String newValue$WatchMethodProperty; + + @JsProperty + String oldValue$WatchMethodProperty; + + @Override + public void created() { + vue().$watch("watchedPropWatchString", (newValue, oldValue) -> { + this.newValue$WatchString = (SimpleObject) newValue; + this.oldValue$WatchString = (SimpleObject) oldValue; + }); + vue().$watch("watchedPropWatchString.stringProperty", (newValue, oldValue) -> { + this.newValue$WatchStringProperty = (String) newValue; + this.oldValue$WatchStringProperty = (String) oldValue; + }); + + vue().$watch(() -> watchedPropWatchMethod, (newValue, oldValue) -> { + this.newValue$WatchMethod = newValue; + this.oldValue$WatchMethod = oldValue; + }); + vue().$watch( + () -> { + if (watchedPropWatchMethod == null) { + return null; + } + return watchedPropWatchMethod.getStringProperty(); + }, + (newValue, oldValue) -> { + this.newValue$WatchMethodProperty = newValue; + this.oldValue$WatchMethodProperty = oldValue; + } + ); + } + + @Watch("watchedPropAnnotation") + public void onwatchedPropChange(SimpleObject newValue, SimpleObject oldValue) { + this.newValueAnnotation = newValue; + this.oldValueAnnotation = oldValue; + } + + @Watch("watchedPropAnnotation.stringProperty") + public void onwatchedPropPropertyChange(String newValue, String oldValue) { + this.newValueAnnotationProperty = newValue; + this.oldValueAnnotationProperty = oldValue; + } + + @Watch(value = "watchedPropDeepAnnotation", isDeep = true) + public void onWatchedPropDeepChange(SimpleObject newValue, SimpleObject oldValue) { + this.newValueAnnotationDeep = newValue != null ? newValue.getStringProperty() : null; + this.oldValueAnnotationDeep = oldValue != null ? oldValue.getStringProperty() : null; + } +} diff --git a/tests/src/test/javascript/components/basic/computed.spec.js b/tests/src/test/javascript/components/basic/computed.spec.js index a20317a4..e02b4473 100644 --- a/tests/src/test/javascript/components/basic/computed.spec.js +++ b/tests/src/test/javascript/components/basic/computed.spec.js @@ -1,7 +1,9 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('@Computed', () => { @@ -24,7 +26,7 @@ describe('@Computed', () => { it('should change its value when a depending value changes', () => { component.data = 'test value'; - return onNextTick(() => { + return nextTick().then(() => { expect(component.$el.innerText).to.equal('#test value#'); expect(component.$el.getAttribute('data-value')).to.equal('#test value#') }); diff --git a/tests/src/test/javascript/components/basic/data.spec.js b/tests/src/test/javascript/components/basic/data.spec.js index 01e0c584..720d366c 100644 --- a/tests/src/test/javascript/components/basic/data.spec.js +++ b/tests/src/test/javascript/components/basic/data.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('Data', () => { @@ -24,7 +27,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.byteData = 127; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#byte-data').innerText; expect(domValue).to.equal('127'); }) @@ -39,7 +42,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.shortData = 6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#short-data').innerText; expect(domValue).to.equal('6'); }); @@ -54,7 +57,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.intData = 6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#int-data').innerText; expect(domValue).to.equal('6'); }); @@ -69,7 +72,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.longData = 6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#long-data').innerText; expect(domValue).to.equal('6'); }); @@ -84,7 +87,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.floatData = 6.6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#float-data').innerText; expect(domValue).to.equal('6.6'); }); @@ -99,7 +102,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.doubleData = 6.6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#double-data').innerText; expect(domValue).to.equal('6.6'); }); @@ -114,7 +117,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.booleanData = true; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#boolean-data').innerText; expect(domValue).to.equal('true'); }); @@ -129,7 +132,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.assignVToCharData(); - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#char-data').innerText; expect(domValue).to.equal('v'); }); @@ -152,7 +155,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.byteObjectData = 127; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#byte-object-data').innerText; expect(domValue).to.equal('127'); }); @@ -168,7 +171,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.shortObjectData = 6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#short-object-data').innerText; expect(domValue).to.equal('6'); }); @@ -184,7 +187,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.integerData = 6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#integer-data').innerText; expect(domValue).to.equal('6'); }); @@ -200,7 +203,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.longObjectData = 6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#long-object-data').innerText; expect(domValue).to.equal('6'); }); @@ -216,7 +219,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.floatObjectData = 6.6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#float-object-data').innerText; expect(domValue).to.equal('6.6'); }); @@ -232,7 +235,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.doubleObjectData = 6.6; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#double-object-data').innerText; expect(domValue).to.equal('6.6'); }); @@ -248,7 +251,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.characterData = 'v'; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#character-data').innerText; expect(domValue).to.equal('v'); }); @@ -264,7 +267,7 @@ describe('Data', () => { it('should update its DOM element when it changes', () => { component.stringData = 'a value'; - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#string-data').innerText; expect(domValue).to.equal('a value'); }); @@ -280,7 +283,7 @@ describe('Data', () => { it('should be displayed as empty string when its property is null', () => { component.initSimpleObject(); - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#simple-object-data').innerText; expect(domValue).to.equal(''); }); @@ -290,7 +293,7 @@ describe('Data', () => { component.initSimpleObject(); component.simpleObjectData.setStringProperty('a value'); - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#simple-object-data').innerText; expect(domValue).to.equal('a value'); }); @@ -306,7 +309,7 @@ describe('Data', () => { it('should be displayed in the DOM if its value is not null', () => { component.attributeValueData = 'a value'; - return onNextTick(() => { + return nextTick().then(() => { const element = getElement(component, '#data-attribute-element'); expect(element.getAttribute('data-value')).to.equal('a value'); }); @@ -317,7 +320,7 @@ describe('Data', () => { it('should ignore white spaces', () => { component.dataWithLineBreaks.setStringProperty('a value'); - return onNextTick(() => { + return nextTick().then(() => { const domValue = getElement(component, '#data-with-line-breaks').innerText; expect(domValue).to.equals('a value'); diff --git a/tests/src/test/javascript/components/basic/prop.spec.js b/tests/src/test/javascript/components/basic/prop.spec.js index 9f26adef..7e2f1924 100644 --- a/tests/src/test/javascript/components/basic/prop.spec.js +++ b/tests/src/test/javascript/components/basic/prop.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('@Prop', () => { @@ -30,7 +33,7 @@ describe('@Prop', () => { component.optionalPropParent = 16; component.requiredPropParent.setStringProperty('value'); - return onNextTick(() => { + return nextTick().then(() => { const optionalPropDomValue = getElement(component, '#optional-prop').innerText; const requiredPropDomValue = getElement(component, diff --git a/tests/src/test/javascript/components/basic/propdefault.spec.js b/tests/src/test/javascript/components/basic/propdefault.spec.js index 5f24ae89..7c912603 100644 --- a/tests/src/test/javascript/components/basic/propdefault.spec.js +++ b/tests/src/test/javascript/components/basic/propdefault.spec.js @@ -1,7 +1,9 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady } from '../../vue-gwt-tests-utils' describe('@PropDefault', () => { diff --git a/tests/src/test/javascript/components/basic/propvalidator.spec.js b/tests/src/test/javascript/components/basic/propvalidator.spec.js index 6e7e6013..3d4cf090 100644 --- a/tests/src/test/javascript/components/basic/propvalidator.spec.js +++ b/tests/src/test/javascript/components/basic/propvalidator.spec.js @@ -4,7 +4,7 @@ import spies from 'chai-spies' import { createAndMountComponent, destroyComponent, onGwtReady, - onNextTick + nextTick } from '../../vue-gwt-tests-utils' describe('@PropValidator', () => { @@ -25,7 +25,7 @@ describe('@PropValidator', () => { it('should not fire an error if the value is correct', () => { component.validatedPropParent = 6; - return onNextTick(() => { + return nextTick().then(() => { expect(console.error).to.not.have.been.called(); }); }); @@ -33,7 +33,7 @@ describe('@PropValidator', () => { it('should fire an error if the value is incorrect in dev mode', () => { if (Vue.config.productionTip === true) { component.validatedPropParent = 106; - return onNextTick(() => { + return nextTick().then(() => { expect(console.error).to.have.been.called.once; }); } @@ -42,7 +42,7 @@ describe('@PropValidator', () => { it('should not fire an error if the value is incorrect in production mode', () => { if (Vue.config.productionTip === false) { component.validatedPropParent = 106; - return onNextTick(() => { + return nextTick().then(() => { expect(console.error).to.not.have.been.called(); }); } diff --git a/tests/src/test/javascript/components/basic/watch.spec.js b/tests/src/test/javascript/components/basic/watch.spec.js index 64572738..c18936d7 100644 --- a/tests/src/test/javascript/components/basic/watch.spec.js +++ b/tests/src/test/javascript/components/basic/watch.spec.js @@ -1,36 +1,513 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + nextTick, + onGwtReady } from '../../vue-gwt-tests-utils' -describe('@Watch', () => { - let component; +describe('Watch', () => { + describe('Watch Data', () => { + let component; - beforeEach(() => onGwtReady().then(() => { - component = createAndMountComponent( - 'com.axellience.vuegwt.tests.client.components.basic.watch.WatchTestComponent'); - })); + beforeEach(() => onGwtReady().then(() => { + component = createAndMountComponent( + 'com.axellience.vuegwt.tests.client.components.basic.watch.data.WatchDataTestComponent'); + })); - afterEach(() => { - destroyComponent(component); + afterEach(() => { + destroyComponent(component); + }); + + describe('@Watch', () => { + it('should be called when watching data and data changes', () => { + component.changeWatchedDataAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotation).to.be.null; + expect(component.newValueAnnotation).to.be.not.null; + expect(component.newValueAnnotation.getStringProperty()).to.equal( + 'value'); + + component.changeWatchedDataAnnotation(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotation).to.be.not.null; + expect(component.oldValueAnnotation.getStringProperty()).to.equal( + 'value'); + expect(component.newValueAnnotation).to.be.null; + }) + }); + + it('should be called when watching property on data and data changes', + () => { + component.changeWatchedDataAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.undefined; + expect(component.newValueAnnotationProperty).to.be.not.null; + expect(component.newValueAnnotationProperty).to.equal('value'); + + component.changeWatchedDataAnnotation(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.not.null; + expect(component.oldValueAnnotationProperty).to.equal('value'); + expect(component.newValueAnnotationProperty).to.be.undefined; + }); + }); + + it('should be called when watching property on data and property changes', + () => { + component.changeWatchedDataAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.undefined; + expect(component.newValueAnnotationProperty).to.be.not.null; + expect(component.newValueAnnotationProperty).to.equal('value'); + + component.watchedDataAnnotation.setStringProperty('newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.not.null; + expect(component.oldValueAnnotationProperty).to.equal('value'); + expect(component.newValueAnnotationProperty).to.be.not.null; + expect(component.newValueAnnotationProperty).to.equal('newValue'); + }) + }); + + it('should be called when watching data deep and data changes', () => { + component.changeWatchedDataDeepAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.null; + expect(component.newValueAnnotationDeep).to.be.not.null; + expect(component.newValueAnnotationDeep).to.equal('value'); + + component.changeWatchedDataDeepAnnotation(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.not.null; + expect(component.oldValueAnnotationDeep).to.equal('value'); + expect(component.newValueAnnotationDeep).to.be.null; + }); + }); + + it('should be called when watching data deep and property on data changes', + () => { + component.changeWatchedDataDeepAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.null; + expect(component.newValueAnnotationDeep).to.be.not.null; + expect(component.newValueAnnotationDeep).to.equal('value'); + + component.watchedDataDeepAnnotation.setStringProperty('newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.not.null; + // Same object is passed as old, as the props as changed on it we get "newValue" too in old value + expect(component.oldValueAnnotationDeep).to.equal('newValue'); + expect(component.newValueAnnotationDeep).to.be.not.null; + expect(component.newValueAnnotationDeep).to.equal('newValue'); + }); + }); + }); + + describe('$watch with string', () => { + it('should be called when watching data and data changes', () => { + component.changeWatchedData$WatchString('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchString).to.be.null; + expect(component.newValue$WatchString).to.be.not.null; + expect(component.newValue$WatchString.getStringProperty()).to.equal( + 'value'); + + component.changeWatchedData$WatchString(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchString).to.be.not.null; + expect(component.oldValue$WatchString.getStringProperty()).to.equal( + 'value'); + expect(component.newValue$WatchString).to.be.null; + }) + }); + + it('should be called when watching property on data and data changes', + () => { + component.changeWatchedData$WatchString('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.undefined; + expect(component.newValue$WatchStringProperty).to.be.not.null; + expect(component.newValue$WatchStringProperty).to.equal('value'); + + component.changeWatchedData$WatchString(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.not.null; + expect(component.oldValue$WatchStringProperty).to.equal( + 'value'); + expect(component.newValue$WatchStringProperty).to.be.undefined; + }); + }); + + it('should be called when watching property on data and data changes', + () => { + component.changeWatchedData$WatchString('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.undefined; + expect(component.newValue$WatchStringProperty).to.be.not.null; + expect(component.newValue$WatchStringProperty).to.equal('value'); + + component.watchedData$WatchString.setStringProperty('newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.not.null; + expect(component.oldValue$WatchStringProperty).to.equal('value'); + expect(component.newValue$WatchStringProperty).to.be.not.null; + expect(component.newValue$WatchStringProperty).to.equal( + 'newValue'); + }); + }); + }); + + describe('$watch with method', () => { + it('should be called when watching data and data changes', () => { + component.changeWatchedData$WatchMethod('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchMethod).to.be.null; + expect(component.newValue$WatchMethod).to.be.not.null; + expect(component.newValue$WatchMethod.getStringProperty()).to.equal( + 'value'); + + component.changeWatchedData$WatchMethod(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchMethod).to.be.not.null; + expect(component.oldValue$WatchMethod.getStringProperty()).to.equal( + 'value'); + expect(component.newValue$WatchMethod).to.be.null; + }) + }); + + it('should be called when watching property on data and data changes', + () => { + component.changeWatchedData$WatchMethod('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.null; + expect(component.newValue$WatchMethodProperty).to.be.not.null; + expect(component.newValue$WatchMethodProperty).to.equal('value'); + + component.changeWatchedData$WatchMethod(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.not.null; + expect(component.oldValue$WatchMethodProperty).to.equal( + 'value'); + expect(component.newValue$WatchMethodProperty).to.be.null; + }); + }); + + it('should be called when watching property on data and property changes', + () => { + component.changeWatchedData$WatchMethod('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.null; + expect(component.newValue$WatchMethodProperty).to.be.not.null; + expect(component.newValue$WatchMethodProperty).to.equal('value'); + + component.watchedData$WatchMethod.setStringProperty('newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.not.null; + expect(component.oldValue$WatchMethodProperty).to.equal('value'); + expect(component.newValue$WatchMethodProperty).to.be.not.null; + expect(component.newValue$WatchMethodProperty).to.equal( + 'newValue'); + }); + }); + }); }); - it('should be called with correct parameters when the data change', () => { - component.changeWatchedData('value'); - - return onNextTick(() => { - expect(component.oldValue).to.be.null; - expect(component.newValue).to.be.not.null; - expect(component.newValue.getStringProperty()).to.equal('value'); - }) - .then(() => { - component.changeWatchedData(null); - return onNextTick(() => { - expect(component.oldValue).to.be.not.null; - expect(component.oldValue.getStringProperty()).to.equal('value'); - expect(component.newValue).to.be.null; - }) + describe('Watch Prop', () => { + let parentComponent; + let component; + + beforeEach(() => onGwtReady().then(() => { + parentComponent = createAndMountComponent( + 'com.axellience.vuegwt.tests.client.components.basic.watch.prop.WatchPropParentTestComponent'); + component = parentComponent.getWatchPropTestComponent(); + })); + + afterEach(() => { + destroyComponent(parentComponent); + }); + + describe('@Watch', () => { + it('should be called when watching @Prop and @Prop changes', () => { + parentComponent.changeWatchedPropAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotation).to.be.null; + expect(component.newValueAnnotation).to.be.not.null; + expect(component.newValueAnnotation.getStringProperty()).to.equal( + 'value'); + + parentComponent.changeWatchedPropAnnotation(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotation).to.be.not.null; + expect(component.oldValueAnnotation.getStringProperty()).to.equal( + 'value'); + expect(component.newValueAnnotation).to.be.null; + }) + }); + + it('should be called when watching property on @Prop and @Prop changes', + () => { + parentComponent.changeWatchedPropAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.undefined; + expect(component.newValueAnnotationProperty).to.be.not.null; + expect(component.newValueAnnotationProperty).to.equal('value'); + + parentComponent.changeWatchedPropAnnotation(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.not.null; + expect(component.oldValueAnnotationProperty).to.equal('value'); + expect(component.newValueAnnotationProperty).to.be.undefined; + }); + }); + + it('should be called when watching property on @Prop and property changes', + () => { + parentComponent.changeWatchedPropAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.undefined; + expect(component.newValueAnnotationProperty).to.be.not.null; + expect(component.newValueAnnotationProperty).to.equal('value'); + + parentComponent.watchedPropAnnotation.setStringProperty( + 'newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationProperty).to.be.not.null; + expect(component.oldValueAnnotationProperty).to.equal('value'); + expect(component.newValueAnnotationProperty).to.be.not.null; + expect(component.newValueAnnotationProperty).to.equal('newValue'); + }); + }); + + it('should be called when watching @Prop deep and @Prop changes', () => { + parentComponent.changeWatchedPropDeepAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.null; + expect(component.newValueAnnotationDeep).to.be.not.null; + expect(component.newValueAnnotationDeep).to.equal('value'); + + parentComponent.changeWatchedPropDeepAnnotation(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.not.null; + expect(component.oldValueAnnotationDeep).to.equal('value'); + expect(component.newValueAnnotationDeep).to.be.null; + }); + }); + + it('should be called when watching @Prop deep and property on @Prop changes', + () => { + parentComponent.changeWatchedPropDeepAnnotation('value'); + + return nextTick() + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.null; + expect(component.newValueAnnotationDeep).to.be.not.null; + expect(component.newValueAnnotationDeep).to.equal('value'); + + parentComponent.watchedPropDeepAnnotation.setStringProperty('newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValueAnnotationDeep).to.be.not.null; + // Same object is passed as old, as the props as changed on it we get "newValue" too in old value + expect(component.oldValueAnnotationDeep).to.equal('newValue'); + expect(component.newValueAnnotationDeep).to.be.not.null; + expect(component.newValueAnnotationDeep).to.equal('newValue'); + }); + }); + }); + + describe('$watch with string', () => { + it('should be called when watching @Prop and @Prop changes', () => { + parentComponent.changeWatchedProp$WatchString('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchString).to.be.null; + expect(component.newValue$WatchString).to.be.not.null; + expect(component.newValue$WatchString.getStringProperty()).to.equal( + 'value'); + + parentComponent.changeWatchedProp$WatchString(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchString).to.be.not.null; + expect(component.oldValue$WatchString.getStringProperty()).to.equal( + 'value'); + expect(component.newValue$WatchString).to.be.null; + }) + }); + + it('should be called when watching property on @Prop and @Prop changes', + () => { + parentComponent.changeWatchedProp$WatchString('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.undefined; + expect(component.newValue$WatchStringProperty).to.be.not.null; + expect(component.newValue$WatchStringProperty).to.equal('value'); + + parentComponent.changeWatchedProp$WatchString(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.not.null; + expect(component.oldValue$WatchStringProperty).to.equal( + 'value'); + expect(component.newValue$WatchStringProperty).to.be.undefined; + }); + }); + + it('should be called when watching property on @Prop and property changes', + () => { + parentComponent.changeWatchedProp$WatchString('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.undefined; + expect(component.newValue$WatchStringProperty).to.be.not.null; + expect(component.newValue$WatchStringProperty).to.equal('value'); + + parentComponent.watchedProp$WatchString.setStringProperty('newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchStringProperty).to.be.not.null; + expect(component.oldValue$WatchStringProperty).to.equal('value'); + expect(component.newValue$WatchStringProperty).to.be.not.null; + expect(component.newValue$WatchStringProperty).to.equal( + 'newValue'); + }); + }); + }); + + describe('$watch with method', () => { + it('should be called when watching @Prop and @Prop changes', () => { + parentComponent.changeWatchedProp$WatchMethod('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchMethod).to.be.null; + expect(component.newValue$WatchMethod).to.be.not.null; + expect(component.newValue$WatchMethod.getStringProperty()).to.equal( + 'value'); + + parentComponent.changeWatchedProp$WatchMethod(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchMethod).to.be.not.null; + expect(component.oldValue$WatchMethod.getStringProperty()).to.equal( + 'value'); + expect(component.newValue$WatchMethod).to.be.null; + }) + }); + + it('should be called when watching property on @Prop and @Prop changes', + () => { + parentComponent.changeWatchedProp$WatchMethod('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.null; + expect(component.newValue$WatchMethodProperty).to.be.not.null; + expect(component.newValue$WatchMethodProperty).to.equal('value'); + + parentComponent.changeWatchedProp$WatchMethod(null); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.not.null; + expect(component.oldValue$WatchMethodProperty).to.equal( + 'value'); + expect(component.newValue$WatchMethodProperty).to.be.null; + }); + }); + + it('should be called when watching property on @Prop and property changes', + () => { + parentComponent.changeWatchedProp$WatchMethod('value'); + + return nextTick() + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.null; + expect(component.newValue$WatchMethodProperty).to.be.not.null; + expect(component.newValue$WatchMethodProperty).to.equal('value'); + + parentComponent.watchedProp$WatchMethod.setStringProperty( + 'newValue'); + return nextTick(); + }) + .then(() => { + expect(component.oldValue$WatchMethodProperty).to.be.not.null; + expect(component.oldValue$WatchMethodProperty).to.equal('value'); + expect(component.newValue$WatchMethodProperty).to.be.not.null; + expect(component.newValue$WatchMethodProperty).to.equal( + 'newValue'); + }); + }); }); }); }); \ No newline at end of file diff --git a/tests/src/test/javascript/components/conditionalrendering/vif.spec.js b/tests/src/test/javascript/components/conditionalrendering/vif.spec.js index f5b94f9a..c68870e1 100644 --- a/tests/src/test/javascript/components/conditionalrendering/vif.spec.js +++ b/tests/src/test/javascript/components/conditionalrendering/vif.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('v-if', () => { @@ -21,7 +24,7 @@ describe('v-if', () => { expect(getElement(component, '#if-element')).to.be.null; component.ifCondition = true; - return onNextTick(() => { + return nextTick().then(() => { expect(getElement(component, '#if-element')).to.exist; }); }); @@ -31,7 +34,7 @@ describe('v-if', () => { expect(getElement(component, '#if-else--else-element')).to.exist; component.ifCondition = true; - return onNextTick(() => { + return nextTick().then(() => { expect(getElement(component, '#if-else--if-element')).to.exist; expect(getElement(component, '#if-else--else-element')).to.be.null; }); @@ -44,17 +47,19 @@ describe('v-if', () => { component.ifCondition = true; component.elseIfCondition = true; - return onNextTick(() => { + return nextTick() + .then(() => { expect(getElement(component, '#if-else-if--if-element')).to.exist; expect(getElement(component, '#if-else-if--else-if-element')).to.be.null; expect(getElement(component, '#if-else-if--else-element')).to.be.null; - }).then(() => { + component.ifCondition = false; - return onNextTick(() => { - expect(getElement(component, '#if-else-if--if-element')).to.be.null; - expect(getElement(component, '#if-else-if--else-if-element')).to.exist; - expect(getElement(component, '#if-else-if--else-element')).to.be.null; - }); + return nextTick(); + }) + .then(() => { + expect(getElement(component, '#if-else-if--if-element')).to.be.null; + expect(getElement(component, '#if-else-if--else-if-element')).to.exist; + expect(getElement(component, '#if-else-if--else-element')).to.be.null; }); }); }); \ No newline at end of file diff --git a/tests/src/test/javascript/components/conditionalrendering/vshow.spec.js b/tests/src/test/javascript/components/conditionalrendering/vshow.spec.js index fecd18c0..c6f6417a 100644 --- a/tests/src/test/javascript/components/conditionalrendering/vshow.spec.js +++ b/tests/src/test/javascript/components/conditionalrendering/vshow.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('v-show', () => { @@ -25,7 +28,7 @@ describe('v-show', () => { it('should show its element if its condition is true', () => { const showElement = getElement(component, '#show-element'); component.showCondition = true; - return onNextTick(() => { + return nextTick().then(() => { expect(showElement.style.display).to.be.empty; }); }); diff --git a/tests/src/test/javascript/components/events/types/EventTypes.spec.js b/tests/src/test/javascript/components/events/types/EventTypes.spec.js index 84b042f0..dea9c16d 100644 --- a/tests/src/test/javascript/components/events/types/EventTypes.spec.js +++ b/tests/src/test/javascript/components/events/types/EventTypes.spec.js @@ -1,25 +1,30 @@ import {expect} from 'chai' -import {createAndMountComponent, onGwtReady, vueGwtTests} from '../../../vue-gwt-tests-utils' +import { + createAndMountComponent, + onGwtReady, + vueGwtTests +} from '../../../vue-gwt-tests-utils' describe('EventTypes.spec', () => { - let vm; + let vm; - beforeEach(() => onGwtReady().then(() => { - vm = createAndMountComponent("com.axellience.vuegwt.tests.client.components.events.types.EmitTypesParentComponent") - })); + beforeEach(() => onGwtReady().then(() => { + vm = createAndMountComponent( + "com.axellience.vuegwt.tests.client.components.events.types.EmitTypesParentComponent") + })); - it("doesn't box primitive types", () => { - expect(vm.myInt).to.equal(10); - expect(vm.myBoolean).to.equal(false); - expect(vm.myDouble).to.equal(12); - expect(vm.myFloat).to.equal(12.5); - }); + it("doesn't box primitive types", () => { + expect(vm.myInt).to.equal(10); + expect(vm.myBoolean).to.equal(false); + expect(vm.myDouble).to.equal(12); + expect(vm.myFloat).to.equal(12.5); + }); - it("doesn't unbox boxed types", () => { - expect(vm.getMyInteger()).to.deep.equal(vm.getTestIntegerValue()); - }); + it("doesn't unbox boxed types", () => { + expect(vm.getMyInteger()).to.deep.equal(vm.getTestIntegerValue()); + }); - it("passes objects untouched", () => { - expect(vm.myTodo.text).to.equal("Hello World"); - }); + it("passes objects untouched", () => { + expect(vm.myTodo.text).to.equal("Hello World"); + }); }); \ No newline at end of file diff --git a/tests/src/test/javascript/components/style/classbinding.spec.js b/tests/src/test/javascript/components/style/classbinding.spec.js index e27127a5..8b69f510 100644 --- a/tests/src/test/javascript/components/style/classbinding.spec.js +++ b/tests/src/test/javascript/components/style/classbinding.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('Class binding', () => { @@ -21,7 +24,7 @@ describe('Class binding', () => { expect(classAElement.getAttribute('class')).to.be.empty; component.hasClassA = true; - return onNextTick(() => { + return nextTick().then(() => { expect(classAElement.getAttribute('class')).to.equal('class-a'); }); }); @@ -31,16 +34,18 @@ describe('Class binding', () => { expect(classABElement.getAttribute('class')).to.be.empty; component.hasClassB = true; - return onNextTick(() => { + return nextTick() + .then(() => { const classValue = classABElement.getAttribute('class'); expect(classValue).to.equal('class-b'); - }).then(() => { + component.hasClassA = true; - return onNextTick(() => { - const classValue = classABElement.getAttribute('class'); - expect(classValue).to.have.string('class-a'); - expect(classValue).to.have.string('class-b'); - }); + return nextTick(); + }) + .then(() => { + const classValue = classABElement.getAttribute('class'); + expect(classValue).to.have.string('class-a'); + expect(classValue).to.have.string('class-b'); }); }); @@ -50,16 +55,18 @@ describe('Class binding', () => { expect(computedClassABElement.getAttribute('class')).to.be.empty; component.hasClassB = true; - return onNextTick(() => { + return nextTick() + .then(() => { const classValue = computedClassABElement.getAttribute('class'); expect(classValue).to.equal('class-b'); - }).then(() => { + component.hasClassA = true; - return onNextTick(() => { - const classValue = computedClassABElement.getAttribute('class'); - expect(classValue).to.have.string('class-a'); - expect(classValue).to.have.string('class-b'); - }); + return nextTick(); + }) + .then(() => { + const classValue = computedClassABElement.getAttribute('class'); + expect(classValue).to.have.string('class-a'); + expect(classValue).to.have.string('class-b'); }); }); @@ -68,7 +75,7 @@ describe('Class binding', () => { expect(staticClassElement.getAttribute('class')).to.equal('static-class'); component.hasClassA = true; - return onNextTick(() => { + return nextTick().then(() => { const classValue = staticClassElement.getAttribute('class'); expect(classValue).to.have.string('static-class'); expect(classValue).to.have.string('class-a'); @@ -80,7 +87,7 @@ describe('Class binding', () => { expect(arrayClassElement.getAttribute('class')).to.equal('class-c'); component.hasClassA = true; - return onNextTick(() => { + return nextTick().then(() => { const classValue = arrayClassElement.getAttribute('class'); expect(classValue).to.have.string('class-c'); expect(classValue).to.have.string('class-a'); diff --git a/tests/src/test/javascript/components/style/inlinestylebinding.spec.js b/tests/src/test/javascript/components/style/inlinestylebinding.spec.js index 625e55f9..24addf2b 100644 --- a/tests/src/test/javascript/components/style/inlinestylebinding.spec.js +++ b/tests/src/test/javascript/components/style/inlinestylebinding.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + onGwtReady, + nextTick } from '../../vue-gwt-tests-utils' describe('Inline style binding', () => { @@ -21,7 +24,7 @@ describe('Inline style binding', () => { expect(element.getAttribute('style')).to.equal('color: black;'); component.color = 'white'; - return onNextTick(() => { + return nextTick().then(() => { expect(element.getAttribute('style')).to.equal('color: white;'); }); }); @@ -34,7 +37,7 @@ describe('Inline style binding', () => { component.color = 'white'; component.fontSize = 14; - return onNextTick(() => { + return nextTick().then(() => { const styleAttribute = element.getAttribute('style'); expect(styleAttribute).to.have.string('color: white;'); expect(styleAttribute).to.have.string('font-size: 14px;'); diff --git a/tests/src/test/javascript/vue-gwt-tests-utils.js b/tests/src/test/javascript/vue-gwt-tests-utils.js index f7b1f4fa..5722689c 100644 --- a/tests/src/test/javascript/vue-gwt-tests-utils.js +++ b/tests/src/test/javascript/vue-gwt-tests-utils.js @@ -23,17 +23,8 @@ export const destroyComponent = function (component) { document.body.removeChild(component.$el); }; -export const onNextTick = function (testFunction) { - return new Promise((resolve, reject) => { - Vue.nextTick(() => { - try { - testFunction(); - resolve(); - } catch (e) { - reject(e); - } - }); - }); +export const nextTick = function () { + return Vue.nextTick(); }; export const getElement = function (component, query) { From c4e228841ad1353f85f1d27efdcf9a2eaecb98f1 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Wed, 13 Jun 2018 15:10:52 +0200 Subject: [PATCH 11/76] tests: update scoped style test to use the new nextTick method --- .../components/style/scoped.spec.js | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/src/test/javascript/components/style/scoped.spec.js b/tests/src/test/javascript/components/style/scoped.spec.js index cd4c5120..ab84ee9a 100644 --- a/tests/src/test/javascript/components/style/scoped.spec.js +++ b/tests/src/test/javascript/components/style/scoped.spec.js @@ -1,7 +1,10 @@ import {expect} from 'chai' import { - createAndMountComponent, destroyComponent, getElement, onGwtReady, - onNextTick + createAndMountComponent, + destroyComponent, + getElement, + nextTick, + onGwtReady } from '../../vue-gwt-tests-utils' describe('Scoped styling', () => { @@ -18,22 +21,25 @@ describe('Scoped styling', () => { it('check non-boiling label has proper styling', () => { component.celsius = '22'; - return onNextTick(() => { + return nextTick().then(() => { const element = getElement(component, '.relax'); expect(element).to.exist; - const c = window.getComputedStyle(element, null).getPropertyValue('color'); + const c = window.getComputedStyle(element, null).getPropertyValue( + 'color'); expect(c).to.equal('rgb(0, 128, 0)'); // green - const b = window.getComputedStyle(element, null).getPropertyValue('border-radius'); - expect(b).to.equal('8px'); // 0.5em + const b = window.getComputedStyle(element, null).getPropertyValue( + 'border-radius'); + expect(b).to.equal('8px'); // 0.5em }); }); it('check boiling label has proper styling', () => { component.celsius = '101'; - return onNextTick(() => { - const element = getElement(component, '.attention'); - expect(element).to.exist; - const c = window.getComputedStyle(element, null).getPropertyValue('color'); + return nextTick().then(() => { + const element = getElement(component, '.attention'); + expect(element).to.exist; + const c = window.getComputedStyle(element, null).getPropertyValue( + 'color'); expect(c).to.equal('rgb(255, 0, 0)'); // red }); }); From 2313b0c4e639f0851a550ee197f5ddf7ebc11bf1 Mon Sep 17 00:00:00 2001 From: adrienbaron Date: Wed, 13 Jun 2018 15:31:49 +0200 Subject: [PATCH 12/76] chore: refactor code to use Google Style Guide --- core/pom.xml | 116 +- .../core/annotations/component/Component.java | 86 +- .../core/annotations/component/Computed.java | 13 +- .../core/annotations/component/Emit.java | 17 +- .../annotations/component/HookMethod.java | 11 +- .../annotations/component/JsComponent.java | 13 +- .../core/annotations/component/Prop.java | 34 +- .../annotations/component/PropDefault.java | 22 +- .../annotations/component/PropValidator.java | 22 +- .../core/annotations/component/Watch.java | 16 +- .../core/annotations/directive/Directive.java | 12 +- .../axellience/vuegwt/core/client/Vue.java | 376 ++--- .../client/VueCustomElementLibInjector.java | 40 +- .../axellience/vuegwt/core/client/VueGWT.java | 431 ++--- .../vuegwt/core/client/VueLibDevInjector.java | 61 +- .../vuegwt/core/client/VueLibInjector.java | 47 +- .../ComponentExposedTypeConstructorFn.java | 66 +- .../core/client/component/IsVueComponent.java | 12 +- .../core/client/component/VueComponent.java | 372 ++--- .../client/component/hooks/HasActivated.java | 10 +- .../component/hooks/HasBeforeCreate.java | 10 +- .../component/hooks/HasBeforeDestroy.java | 10 +- .../component/hooks/HasBeforeMount.java | 10 +- .../component/hooks/HasBeforeUpdate.java | 10 +- .../client/component/hooks/HasCreated.java | 10 +- .../component/hooks/HasDeactivated.java | 10 +- .../client/component/hooks/HasDestroyed.java | 10 +- .../component/hooks/HasErrorCaptured.java | 10 +- .../client/component/hooks/HasMounted.java | 10 +- .../client/component/hooks/HasRender.java | 11 +- .../client/component/hooks/HasUpdated.java | 10 +- .../component/options/CustomizeOptions.java | 6 +- .../options/NamedElementDefinition.java | 27 +- .../options/VueComponentOptions.java | 1037 ++++++------ .../options/computed/ComputedKind.java | 5 +- .../options/computed/ComputedOptions.java | 9 +- .../options/data/DataDefinition.java | 12 +- .../component/options/data/DataFactory.java | 12 +- .../component/options/functions/OnEvent.java | 7 +- .../options/functions/OnNextTick.java | 7 +- .../component/options/props/PropOptions.java | 15 +- .../options/watch/ChangeTrigger.java | 7 +- .../options/watch/OnValueChange.java | 6 +- .../options/watch/WatcherRegistration.java | 7 +- .../AttributeChangedCallback.java | 7 +- .../customelement/CustomElementOptions.java | 201 ++- .../customelement/VueCustomElement.java | 16 +- .../customelement/VueCustomElementType.java | 19 +- .../core/client/directive/VueDirective.java | 39 +- .../options/VueDirectiveOptions.java | 99 +- .../jsnative/jsfunctions/JsConsumer.java | 6 +- .../jsnative/jsfunctions/JsProvider.java | 6 +- .../jsnative/jsfunctions/JsRunnable.java | 6 +- .../core/client/observer/VueGWTObserver.java | 6 +- .../observer/VueGWTObserverManager.java | 382 +++-- .../core/client/observer/VueObserver.java | 46 +- .../client/observer/VueObserverPrototype.java | 8 +- .../observer/functions/VueObserveArray.java | 6 +- .../client/observer/functions/VueWalk.java | 6 +- .../vuegwtobservers/CollectionObserver.java | 142 +- .../observer/vuegwtobservers/MapObserver.java | 90 +- .../core/client/tools/AfterMethodCall.java | 6 +- .../vuegwt/core/client/tools/JsUtils.java | 107 +- .../core/client/tools/VForExpressionUtil.java | 86 +- .../vuegwt/core/client/tools/VueGWTTools.java | 170 +- .../core/client/vnode/InlineTemplate.java | 69 +- .../vuegwt/core/client/vnode/ScopedSlot.java | 6 +- .../vuegwt/core/client/vnode/VNode.java | 429 +++-- .../client/vnode/VNodeComponentOptions.java | 96 +- .../vuegwt/core/client/vnode/VNodeData.java | 781 +++++---- .../core/client/vnode/VNodeDirective.java | 182 +-- .../client/vnode/builder/VNodeBuilder.java | 214 +-- .../core/client/vue/VueComponentFactory.java | 54 +- .../vuegwt/core/client/vue/VueConfig.java | 287 ++-- .../core/client/vue/VueErrorHandler.java | 6 +- .../core/client/vue/VueJsAsyncProvider.java | 12 +- .../core/client/vue/VueJsConstructor.java | 94 +- .../core/client/vue/VueWarnHandler.java | 6 +- .../src/main/java/javax/inject/Inject.gwt.xml | 2 +- core/src/main/module.gwt.xml | 16 +- docs/.vuepress/enhanceApp.js | 6 +- .../client/ExampleInjector.java | 7 +- .../client/JsFilesResources.java | 1 + .../client/VueGwtExamplesApp.java | 33 +- .../client/VueGwtExamplesService.java | 129 +- .../AnimalSelectorComponent.html | 26 +- .../AnimalSelectorComponent.java | 19 +- .../BindInlineStyleComponent.html | 2 +- .../BindInlineStyleComponent.java | 12 +- .../buttonplusone/ButtonPlusOneComponent.html | 4 +- .../buttonplusone/ButtonPlusOneComponent.java | 9 +- .../examples/canhide/CanHideComponent.html | 2 +- .../examples/canhide/CanHideComponent.java | 9 +- .../client/examples/common/Todo.java | 25 +- .../ButtonCounterComponent.java | 20 +- .../CounterWithEventComponent.html | 6 +- .../CounterWithEventComponent.java | 18 +- .../EmitAnnotationComponent.html | 8 +- .../EmitAnnotationComponent.java | 67 +- .../ParentEmitAnnotationComponent.html | 6 +- .../ParentEmitAnnotationComponent.java | 13 +- .../errorboundary/ErrorBoundaryComponent.java | 42 +- .../errorboundary/ErrorMakerComponent.java | 28 +- .../evennumbers/EvenNumbersComponent.html | 2 +- .../evennumbers/EvenNumbersComponent.java | 21 +- .../exclamation/ExclamationComponent.html | 4 +- .../exclamation/ExclamationComponent.java | 18 +- .../extendjavacomponent/ChildComponent.html | 14 +- .../extendjavacomponent/ChildComponent.java | 45 +- .../extendjavacomponent/ParentComponent.java | 27 +- .../ChildJavaComponent.html | 14 +- .../ChildJavaComponent.java | 34 +- .../parent/ParentJsComponent.java | 14 +- .../client/examples/focus/FocusDirective.java | 15 +- .../focus/FocusDirectiveComponent.java | 6 +- .../client/examples/gotquotes/GotQuote.java | 53 +- .../gotquotes/GotQuotesComponent.html | 17 +- .../gotquotes/GotQuotesComponent.java | 35 +- .../examples/gotquotes/GotQuotesService.java | 79 +- .../client/examples/greet/GreetComponent.java | 15 +- .../examples/hiwhat/HiWhatComponent.html | 4 +- .../examples/hiwhat/HiWhatComponent.java | 14 +- .../FullJsWithMethodsComponent.java | 11 +- .../examples/kitten/KittenClientBundle.java | 10 +- .../examples/kitten/KittenComponent.java | 9 +- .../client/examples/link/LinkComponent.html | 2 +- .../client/examples/link/LinkComponent.java | 12 +- .../melisandre/MelisandreComponent.html | 24 +- .../melisandre/MelisandreComponent.java | 16 +- .../MelisandreComponentClientBundle.java | 10 +- .../melisandre/MelisandreComponentStyle.gss | 5 +- .../melisandre/MelisandreComponentStyle.java | 9 +- .../examples/message/MessageComponent.html | 4 +- .../examples/message/MessageComponent.java | 9 +- .../examples/parent/ParentComponent.html | 6 +- .../examples/parent/ParentComponent.java | 6 +- .../client/examples/parent/TodoComponent.html | 2 +- .../client/examples/parent/TodoComponent.java | 6 +- .../passvalues/ParentPassValuesComponent.html | 56 +- .../passvalues/ParentPassValuesComponent.java | 4 +- .../passvalues/PassValuesComponent.html | 10 +- .../passvalues/PassValuesComponent.java | 82 +- .../ParentPropDefaultValueComponent.html | 2 +- .../ParentPropDefaultValueComponent.java | 7 +- .../PropDefaultValueComponent.html | 2 +- .../PropDefaultValueComponent.java | 21 +- .../recursive/RecursiveComponent.java | 19 +- .../examples/reverse/ReverseComponent.html | 4 +- .../examples/reverse/ReverseComponent.java | 18 +- .../SharedDataModelComponent.java | 9 +- .../simplelink/SimpleLinkComponent.html | 2 +- .../simplelink/SimpleLinkComponent.java | 9 +- .../AnchoredHeadingComponent.java | 59 +- .../simplerender/RenderAppComponent.html | 4 +- .../simplerender/RenderAppComponent.java | 6 +- .../SimpleTodoListComponent.html | 6 +- .../SimpleTodoListComponent.java | 25 +- .../examples/todolist/TodoComponent.html | 2 +- .../examples/todolist/TodoComponent.java | 12 +- .../examples/todolist/TodoListComponent.html | 6 +- .../examples/todolist/TodoListComponent.java | 25 +- .../examples/todotext/TodoTextComponent.html | 4 +- .../examples/todotext/TodoTextComponent.java | 18 +- .../TodoTextComputedComponent.html | 4 +- .../TodoTextComputedComponent.java | 27 +- .../client/examples/tree/Folder.java | 55 +- .../client/examples/tree/TreeComponent.java | 36 +- .../examples/tree/TreeFolderComponent.html | 4 +- .../examples/tree/TreeFolderComponent.java | 12 +- .../tree/TreeFolderContentComponent.html | 6 +- .../tree/TreeFolderContentComponent.java | 12 +- .../vforonobject/VForOnObjectComponent.html | 6 +- .../vforonobject/VForOnObjectComponent.java | 24 +- .../VForOnObjectWithKeyComponent.html | 6 +- .../VForOnObjectWithKeyComponent.java | 24 +- .../VForOnObjectWithKeyAndIndexComponent.html | 6 +- .../VForOnObjectWithKeyAndIndexComponent.java | 22 +- .../vforwithindex/VForWithIndexComponent.html | 6 +- .../vforwithindex/VForWithIndexComponent.java | 25 +- .../vforwithrange/VForWithRangeComponent.html | 2 +- .../vforwithrange/VForWithRangeComponent.java | 6 +- .../VOnWithDOMEventComponent.html | 2 +- .../VOnWithDOMEventComponent.java | 22 +- .../vuegwtexamples/client/js-components.js | 12 +- docs/examples/src/main/webapp/WEB-INF/web.xml | 4 +- docs/examples/src/main/webapp/index.html | 189 +-- gwt2/pom.xml | 68 +- .../gwt2/client/widget/VueGwtWidget.java | 90 +- gwt2/src/main/module.gwt.xml | 6 +- pom.xml | 2 +- .../vuegwt/processors/VueGwtProcessor.java | 101 +- .../ComponentExposedTypeGenerator.java | 1432 ++++++++--------- .../ComponentInjectedDependenciesBuilder.java | 372 +++-- .../AbstractVueComponentFactoryGenerator.java | 271 ++-- .../factory/VueComponentFactoryGenerator.java | 471 +++--- .../VueJsComponentFactoryGenerator.java | 134 +- .../template/ComponentTemplateProcessor.java | 429 ++--- .../builder/TemplateMethodsBuilder.java | 298 ++-- .../compiler/NashornVueTemplateCompiler.java | 31 +- .../builder/compiler/VueTemplateCompiler.java | 105 +- .../VueTemplateCompilerException.java | 11 +- .../compiler/VueTemplateCompilerResult.java | 31 +- .../template/parser/TemplateParser.java | 1333 ++++++++------- .../template/parser/TemplateParserLogger.java | 144 +- .../parser/TemplateScopedCssParser.java | 117 +- .../template/parser/VForDefinition.java | 404 +++-- .../template/parser/context/ContextLayer.java | 84 +- .../parser/context/TemplateParserContext.java | 498 +++--- .../localcomponents/LocalComponent.java | 92 +- .../localcomponents/LocalComponentProp.java | 63 +- .../localcomponents/LocalComponents.java | 41 +- .../jericho/TemplateParserLoggerProvider.java | 31 +- .../parser/result/TemplateExpression.java | 219 ++- .../parser/result/TemplateParserResult.java | 149 +- .../parser/variable/LocalVariableInfo.java | 12 +- .../parser/variable/VariableInfo.java | 56 +- .../VueDirectiveOptionsGenerator.java | 85 +- .../utils/ComponentGeneratorsUtil.java | 380 +++-- .../processors/utils/GeneratorsNameUtil.java | 294 ++-- .../processors/utils/GeneratorsUtil.java | 274 ++-- .../utils/InjectedDependenciesUtil.java | 73 +- .../template/parser/TemplateParserTest.java | 10 +- .../validators/DataFieldsValidatorTest.java | 22 +- .../test/resources/common/SimpleObject.java | 1 + .../MustacheExpressionComponent.html | 2 +- .../MustacheExpressionComponent.java | 1 + ...ustacheExpressionComponentExposedType.java | 1 + .../ModelWithIgnoredTypesComponent.java | 1 + ...WithLinkedListWithAnnotationComponent.java | 1 + .../ModelWithListNoAnnotationComponent.java | 1 + .../ModelWithMapNoAnnotationComponent.java | 1 + .../ModelWithSetNoAnnotationComponent.java | 1 + .../ModelWithLinkedListWithAnnotation.java | 1 + .../models/ModelWithListNoAnnotation.java | 1 + .../models/ModelWithMapNoAnnotation.java | 1 + .../models/ModelWithSetNoAnnotation.java | 1 + .../models/ModelWithTypeParameters.java | 3 +- tests/pom.xml | 312 ++-- .../vuegwt/tests/client/VueGwtTestsApp.java | 22 +- .../vuegwt/tests/client/common/Todo.java | 22 +- .../basic/data/DataTestComponent.java | 1 - .../prop/WatchPropParentTestComponent.html | 10 +- .../prop/WatchPropParentTestComponent.java | 1 + .../watch/prop/WatchPropTestComponent.java | 1 + .../events/types/EmitTypesChildComponent.java | 23 +- .../types/EmitTypesParentComponent.html | 14 +- .../types/EmitTypesParentComponent.java | 95 +- .../style/scoped/ScopedTestComponent.html | 2 +- .../style/scoped/ScopedTestComponent.java | 29 +- tests/src/main/module.gwt.xml | 4 +- tests/src/test/javascript/.babelrc | 4 +- .../components/basic/computed.spec.js | 4 +- .../javascript/components/basic/data.spec.js | 4 +- .../javascript/components/basic/prop.spec.js | 4 +- .../components/basic/propvalidator.spec.js | 24 +- .../javascript/components/basic/watch.spec.js | 6 +- .../conditionalrendering/vif.spec.js | 4 +- .../conditionalrendering/vshow.spec.js | 4 +- .../components/style/classbinding.spec.js | 4 +- .../style/inlinestylebinding.spec.js | 4 +- tests/src/test/javascript/delay-promise.js | 2 +- tests/src/test/javascript/karma.conf.ci.js | 16 +- tests/src/test/javascript/karma.conf.js | 52 +- .../test/javascript/karma.conf.superdev.js | 18 +- tests/src/test/javascript/webpack.config.js | 32 +- utils/index.js | 15 +- utils/java/java-string-splitter.js | 29 +- utils/nashorn-template-compiler.js | 16 +- utils/nashorn/nashorn-template-compiler.js | 16 +- .../process-nashorn-template-compiler.js | 60 +- utils/vue-runtime/process-vue-dev-runtime.js | 20 +- utils/vue-runtime/process-vue-runtime.js | 20 +- 272 files changed, 8830 insertions(+), 9055 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 94936b1e..16531dad 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,68 +1,68 @@ - 4.0.0 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - com.axellience - vue-gwt-parent - 1.0-beta-9-SNAPSHOT - + + com.axellience + vue-gwt-parent + 1.0-beta-9-SNAPSHOT + - vue-gwt - Vue GWT - Vue GWT core classes - gwt-lib - - - 1.8 - 1.8 - + vue-gwt + Vue GWT + Vue GWT core classes + gwt-lib - + + 1.8 + 1.8 + - - - com.google.gwt - gwt-user - - - com.google.jsinterop - base - - - com.google.elemental2 - elemental2-core - - - com.google.elemental2 - elemental2-dom - + - - - javax.inject - javax.inject - - - javax.inject - javax.inject - sources - + + + com.google.gwt + gwt-user + + + com.google.jsinterop + base + + + com.google.elemental2 + elemental2-core + + + com.google.elemental2 + elemental2-dom + - + + + javax.inject + javax.inject + + + javax.inject + javax.inject + sources + - - - - net.ltgt.gwt.maven - gwt-maven-plugin - true - - com.axellience.vuegwt.VueGWT - - - - + + + + + + net.ltgt.gwt.maven + gwt-maven-plugin + true + + com.axellience.vuegwt.VueGWT + + + + \ No newline at end of file diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Component.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Component.java index 385e3711..7ac9a095 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Component.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Component.java @@ -1,56 +1,60 @@ package com.axellience.vuegwt.core.annotations.component; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import com.axellience.vuegwt.core.client.component.IsVueComponent; import com.axellience.vuegwt.core.client.component.options.CustomizeOptions; import com.axellience.vuegwt.core.client.directive.VueDirective; - import java.lang.annotation.Retention; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - /** * Annotation placed on Vue Components + * * @author Adrien Baron */ @Target(TYPE) @Retention(RUNTIME) -public @interface Component -{ - String name() default ""; - - /** - * Should use a factory for the data model. - * Passing this to false will make all your components instance share the same data model. - * @return true if we should use a factory, false otherwise - */ - boolean useFactory() default true; - - /** - * Components to register on this component instance - * @return This list of {@link IsVueComponent} to register on this Component - */ - Class[] components() default {}; - - /** - * Directives to register on this component instance - * @return This list of {@link VueDirective} to register on this Component - */ - Class[] directives() default {}; - - /** - * Object responsible to customize the options of the Component. - * This can be used to register routes with Vue router, or more. - * They are injected if the component is injected. - * @return This list of {@link CustomizeOptions} - */ - Class[] customizeOptions() default {}; - - /** - * A flag to set that the component doesn't have a template. - * If the component is abstract, or implement HasRender then it's consider false by default. - * @return true if has a html template, false otherwise - */ - boolean hasTemplate() default true; +public @interface Component { + + String name() default ""; + + /** + * Should use a factory for the data model. Passing this to false will make all your components + * instance share the same data model. + * + * @return true if we should use a factory, false otherwise + */ + boolean useFactory() default true; + + /** + * Components to register on this component instance + * + * @return This list of {@link IsVueComponent} to register on this Component + */ + Class[] components() default {}; + + /** + * Directives to register on this component instance + * + * @return This list of {@link VueDirective} to register on this Component + */ + Class[] directives() default {}; + + /** + * Object responsible to customize the options of the Component. This can be used to register + * routes with Vue router, or more. They are injected if the component is injected. + * + * @return This list of {@link CustomizeOptions} + */ + Class[] customizeOptions() default {}; + + /** + * A flag to set that the component doesn't have a template. If the component is abstract, or + * implement HasRender then it's consider false by default. + * + * @return true if has a html template, false otherwise + */ + boolean hasTemplate() default true; } \ No newline at end of file diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Computed.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Computed.java index 2f84ba24..3c07f504 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Computed.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Computed.java @@ -1,18 +1,19 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.CLASS; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Mark a computed property + * * @author Adrien Baron */ @Target(METHOD) @Retention(CLASS) -public @interface Computed -{ - String value() default ""; +public @interface Computed { + + String value() default ""; } diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Emit.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Emit.java index 09675a44..b23137cd 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Emit.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Emit.java @@ -1,19 +1,18 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.CLASS; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** - * Method annotated with this will emit an event automatically when called - * Similar to @Emit() from vue-property-decorator - * https://github.com/kaorun343/vue-property-decorator + * Method annotated with this will emit an event automatically when called Similar to @Emit() from + * vue-property-decorator https://github.com/kaorun343/vue-property-decorator */ @Target(METHOD) @Retention(CLASS) -public @interface Emit -{ - String value() default ""; +public @interface Emit { + + String value() default ""; } diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/HookMethod.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/HookMethod.java index c9f72cb6..032bae2f 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/HookMethod.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/HookMethod.java @@ -1,15 +1,16 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.CLASS; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * @author Adrien Baron */ @Target(METHOD) @Retention(CLASS) -public @interface HookMethod -{} +public @interface HookMethod { + +} diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/JsComponent.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/JsComponent.java index 9770fba9..d6c84fca 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/JsComponent.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/JsComponent.java @@ -1,18 +1,19 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.SOURCE; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Annotation placed on Vue Components + * * @author Adrien Baron */ @Target(TYPE) @Retention(SOURCE) -public @interface JsComponent -{ - String value(); +public @interface JsComponent { + + String value(); } \ No newline at end of file diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Prop.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Prop.java index d9387a86..d34ac202 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Prop.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Prop.java @@ -1,29 +1,31 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Mark a Java property as being a Vue component Property passed from your Component parent + * * @author Adrien Baron */ @Target(FIELD) @Retention(RUNTIME) -public @interface Prop -{ - /** - * Is the property required - * @return true if the property is required, false otherwise. Default to false. - */ - boolean required() default false; +public @interface Prop { + + /** + * Is the property required + * + * @return true if the property is required, false otherwise. Default to false. + */ + boolean required() default false; - /** - * Should check the type of the property. - * By default check based on the Java type. - * @return true if we should check the type, false otherwise. Default to false. - */ - boolean checkType() default false; + /** + * Should check the type of the property. By default check based on the Java type. + * + * @return true if we should check the type, false otherwise. Default to false. + */ + boolean checkType() default false; } diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropDefault.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropDefault.java index 7956663e..d2cbc634 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropDefault.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropDefault.java @@ -1,22 +1,24 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.SOURCE; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Mark a Java property as being a Vue component Property passed from your Component parent + * * @author Adrien Baron */ @Target(METHOD) @Retention(SOURCE) -public @interface PropDefault -{ - /** - * Name of the property - * @return the name of the property - */ - String value(); +public @interface PropDefault { + + /** + * Name of the property + * + * @return the name of the property + */ + String value(); } diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropValidator.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropValidator.java index 6badc0a4..27afe0d0 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropValidator.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/PropValidator.java @@ -1,22 +1,24 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.SOURCE; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Mark that the given method is used as a validator for the given component property + * * @author Adrien Baron */ @Target(METHOD) @Retention(SOURCE) -public @interface PropValidator -{ - /** - * Name of the property - * @return the name of the property - */ - String value(); +public @interface PropValidator { + + /** + * Name of the property + * + * @return the name of the property + */ + String value(); } diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Watch.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Watch.java index b2639b55..8b7de40f 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Watch.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/component/Watch.java @@ -1,19 +1,21 @@ package com.axellience.vuegwt.core.annotations.component; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.SOURCE; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Mark a watcher for a property of the component data model + * * @author Adrien Baron */ @Target(METHOD) @Retention(SOURCE) -public @interface Watch -{ - String value(); - boolean isDeep() default false; +public @interface Watch { + + String value(); + + boolean isDeep() default false; } diff --git a/core/src/main/java/com/axellience/vuegwt/core/annotations/directive/Directive.java b/core/src/main/java/com/axellience/vuegwt/core/annotations/directive/Directive.java index f23422d7..c112e22e 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/annotations/directive/Directive.java +++ b/core/src/main/java/com/axellience/vuegwt/core/annotations/directive/Directive.java @@ -1,16 +1,18 @@ package com.axellience.vuegwt.core.annotations.directive; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.SOURCE; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + /** * Annotation placed on Vue Directives + * * @author Adrien Baron */ @Target(TYPE) @Retention(SOURCE) -public @interface Directive -{} +public @interface Directive { + +} diff --git a/core/src/main/java/com/axellience/vuegwt/core/client/Vue.java b/core/src/main/java/com/axellience/vuegwt/core/client/Vue.java index c7049f95..bede4184 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/client/Vue.java +++ b/core/src/main/java/com/axellience/vuegwt/core/client/Vue.java @@ -1,5 +1,7 @@ package com.axellience.vuegwt.core.client; +import static com.axellience.vuegwt.core.client.VueGWT.createInstance; + import com.axellience.vuegwt.core.client.component.IsVueComponent; import com.axellience.vuegwt.core.client.component.options.VueComponentOptions; import com.axellience.vuegwt.core.client.customelement.CustomElementOptions; @@ -7,8 +9,8 @@ import com.axellience.vuegwt.core.client.directive.options.VueDirectiveOptions; import com.axellience.vuegwt.core.client.jsnative.jsfunctions.JsRunnable; import com.axellience.vuegwt.core.client.tools.VueGWTTools; -import com.axellience.vuegwt.core.client.vue.VueConfig; import com.axellience.vuegwt.core.client.vue.VueComponentFactory; +import com.axellience.vuegwt.core.client.vue.VueConfig; import com.axellience.vuegwt.core.client.vue.VueJsConstructor; import elemental2.dom.Element; import jsinterop.annotations.JsMethod; @@ -17,190 +19,200 @@ import jsinterop.annotations.JsProperty; import jsinterop.annotations.JsType; -import static com.axellience.vuegwt.core.client.VueGWT.createInstance; - /** * The Java representation of Vue. + * * @author Adrien Baron */ @JsType(isNative = true, namespace = JsPackage.GLOBAL) -public abstract class Vue -{ - @JsProperty private static VueConfig config; - - /** - * Create a {@link Vue} instance and mount it on a DOM element. - * @param element CSS selector for the element to attach in - * @param isVueComponentClass The Class of the Component to create - * @param {@link IsVueComponent} we want to attach - * @return The created and attached instance of our Component - */ - @JsOverlay - public static T attach(String element, Class isVueComponentClass) - { - T vueInstance = createInstance(isVueComponentClass); - vueInstance.vue().$mount(element); - return vueInstance; - } - - /** - * Create a {@link Vue} instance and mount it on a DOM element. - * @param element CSS selector for the element to attach in - * @param vueFactory The factory of the Component to create - * @param {@link IsVueComponent} we want to attach - * @return The created and attached instance of our Component - */ - @JsOverlay - public static T attach(String element, VueComponentFactory vueFactory) - { - T vueInstance = vueFactory.create(); - vueInstance.vue().$mount(element); - return vueInstance; - } - - /** - * Create a {@link Vue} instance and mount it on a DOM element. - * @param element DOM Element we want to attach our component in - * @param isVueComponentClass The Class of the Component to create - * @param {@link IsVueComponent} we want to attach - * @return The created and attached instance of our Component - */ - @JsOverlay - public static T attach(Element element, Class isVueComponentClass) - { - T vueInstance = createInstance(isVueComponentClass); - vueInstance.vue().$mount(element); - return vueInstance; - } - - /** - * Create a {@link Vue} instance and mount it on a DOM element. - * @param element DOM Element we want to attach our component in - * @param vueFactory The factory of the Component to create - * @param {@link IsVueComponent} we want to attach - * @return The created and attached instance of our Component - */ - @JsOverlay - public static T attach(Element element, VueComponentFactory vueFactory) - { - T vueInstance = vueFactory.create(); - vueInstance.vue().$mount(element); - return vueInstance; - } - - /** - * Register a {@link IsVueComponent} globally - * @param id Id for our component in the templates - * @param isVueComponentClass The Class of the {@link IsVueComponent} to create - * @param {@link IsVueComponent} we want to attach - */ - @JsOverlay - public static void component(String id, Class isVueComponentClass) - { - component(id, VueGWT.getVueComponentFactory(isVueComponentClass)); - } - - /** - * Register a {@link IsVueComponent} globally - * @param id Id for our component in the templates - * @param vueFactory The factory of the Component to create - * @param {@link IsVueComponent} we want to attach - */ - @JsOverlay - public static void component(String id, VueComponentFactory vueFactory) - { - component(id, vueFactory.getJsConstructor()); - } - - @JsOverlay - public static VueConfig getConfig() - { - return config; - } - - @JsOverlay - public static void setConfig(VueConfig config) - { - Vue.config = config; - } - - @JsOverlay - public static VueJsConstructor extendJavaComponent( - VueComponentOptions componentOptions) - { - VueJsConstructor extendedVueJsConstructor = extend(componentOptions); - VueGWTTools.extendVueConstructorWithJavaPrototype(extendedVueJsConstructor, - componentOptions.getComponentExportedTypePrototype()); - - return extendedVueJsConstructor; - } - - @JsOverlay - public static VueCustomElementType customElement( - String componentTag, Class isVueComponentClass) - { - return Vue.customElement(componentTag, isVueComponentClass, new CustomElementOptions<>()); - } - - @JsOverlay - public static VueCustomElementType customElement( - String componentTag, VueComponentFactory vueFactory) - { - return Vue.customElement(componentTag, vueFactory, new CustomElementOptions<>()); - } - - @JsOverlay - public static VueCustomElementType customElement( - String componentTag, VueJsConstructor vueJsConstructor) - { - return Vue.customElement(componentTag, vueJsConstructor, new CustomElementOptions<>()); - } - - @JsOverlay - public static VueCustomElementType customElement( - String componentTag, Class isVueComponentClass, CustomElementOptions options) - { - return Vue.customElement(componentTag, VueGWT.getVueComponentFactory(isVueComponentClass), options); - } - - @JsOverlay - public static VueCustomElementType customElement( - String componentTag, VueComponentFactory vueFactory, CustomElementOptions options) - { - return Vue.customElement(componentTag, vueFactory.getJsConstructor(), options); - } - - @JsOverlay - public static VueCustomElementType customElement( - String componentTag, VueJsConstructor vueJsConstructor, CustomElementOptions options) - { - VueCustomElementLibInjector.ensureInjected(); - return Vue.customElementNative(componentTag, vueJsConstructor, options); - } - - // @formatter:off - public static native VueJsConstructor extend(VueComponentOptions componentOptions); - - public static native void nextTick(JsRunnable callback); - - public static native T set(Object object, String key, T value); - public static native boolean set(Object object, String key, boolean value); - public static native byte set(Object object, String key, byte value); - public static native char set(Object object, String key, char value); - public static native float set(Object object, String key, float value); - public static native int set(Object object, String key, int value); - public static native short set(Object object, String key, short value); - public static native double set(Object object, String key, double value); - public static native void delete(Object object, String key); - - public static native void directive(String id, VueDirectiveOptions directiveOptions); - public static native VueDirectiveOptions directive(String id); - - @JsMethod(name = "customElement") - public static native VueCustomElementType customElementNative(String componentTag, VueJsConstructor vueJsConstructor, CustomElementOptions options); - - public static native void component(String id, VueComponentOptions componentOptions); - public static native void component(String id, VueJsConstructor vueJsConstructor); - public static native VueJsConstructor component(String id); - // @formatter:on +public abstract class Vue { + + @JsProperty + private static VueConfig config; + + /** + * Create a {@link Vue} instance and mount it on a DOM element. + * + * @param element CSS selector for the element to attach in + * @param isVueComponentClass The Class of the Component to create + * @param {@link IsVueComponent} we want to attach + * @return The created and attached instance of our Component + */ + @JsOverlay + public static T attach(String element, Class isVueComponentClass) { + T vueInstance = createInstance(isVueComponentClass); + vueInstance.vue().$mount(element); + return vueInstance; + } + + /** + * Create a {@link Vue} instance and mount it on a DOM element. + * + * @param element CSS selector for the element to attach in + * @param vueFactory The factory of the Component to create + * @param {@link IsVueComponent} we want to attach + * @return The created and attached instance of our Component + */ + @JsOverlay + public static T attach(String element, + VueComponentFactory vueFactory) { + T vueInstance = vueFactory.create(); + vueInstance.vue().$mount(element); + return vueInstance; + } + + /** + * Create a {@link Vue} instance and mount it on a DOM element. + * + * @param element DOM Element we want to attach our component in + * @param isVueComponentClass The Class of the Component to create + * @param {@link IsVueComponent} we want to attach + * @return The created and attached instance of our Component + */ + @JsOverlay + public static T attach(Element element, Class isVueComponentClass) { + T vueInstance = createInstance(isVueComponentClass); + vueInstance.vue().$mount(element); + return vueInstance; + } + + /** + * Create a {@link Vue} instance and mount it on a DOM element. + * + * @param element DOM Element we want to attach our component in + * @param vueFactory The factory of the Component to create + * @param {@link IsVueComponent} we want to attach + * @return The created and attached instance of our Component + */ + @JsOverlay + public static T attach(Element element, + VueComponentFactory vueFactory) { + T vueInstance = vueFactory.create(); + vueInstance.vue().$mount(element); + return vueInstance; + } + + /** + * Register a {@link IsVueComponent} globally + * + * @param id Id for our component in the templates + * @param isVueComponentClass The Class of the {@link IsVueComponent} to create + * @param {@link IsVueComponent} we want to attach + */ + @JsOverlay + public static void component(String id, Class isVueComponentClass) { + component(id, VueGWT.getVueComponentFactory(isVueComponentClass)); + } + + /** + * Register a {@link IsVueComponent} globally + * + * @param id Id for our component in the templates + * @param vueFactory The factory of the Component to create + * @param {@link IsVueComponent} we want to attach + */ + @JsOverlay + public static void component(String id, + VueComponentFactory vueFactory) { + component(id, vueFactory.getJsConstructor()); + } + + @JsOverlay + public static VueConfig getConfig() { + return config; + } + + @JsOverlay + public static void setConfig(VueConfig config) { + Vue.config = config; + } + + @JsOverlay + public static VueJsConstructor extendJavaComponent( + VueComponentOptions componentOptions) { + VueJsConstructor extendedVueJsConstructor = extend(componentOptions); + VueGWTTools.extendVueConstructorWithJavaPrototype(extendedVueJsConstructor, + componentOptions.getComponentExportedTypePrototype()); + + return extendedVueJsConstructor; + } + + @JsOverlay + public static VueCustomElementType customElement( + String componentTag, Class isVueComponentClass) { + return Vue.customElement(componentTag, isVueComponentClass, new CustomElementOptions<>()); + } + + @JsOverlay + public static VueCustomElementType customElement( + String componentTag, VueComponentFactory vueFactory) { + return Vue.customElement(componentTag, vueFactory, new CustomElementOptions<>()); + } + + @JsOverlay + public static VueCustomElementType customElement( + String componentTag, VueJsConstructor vueJsConstructor) { + return Vue.customElement(componentTag, vueJsConstructor, new CustomElementOptions<>()); + } + + @JsOverlay + public static VueCustomElementType customElement( + String componentTag, Class isVueComponentClass, CustomElementOptions options) { + return Vue + .customElement(componentTag, VueGWT.getVueComponentFactory(isVueComponentClass), options); + } + + @JsOverlay + public static VueCustomElementType customElement( + String componentTag, VueComponentFactory vueFactory, CustomElementOptions options) { + return Vue.customElement(componentTag, vueFactory.getJsConstructor(), options); + } + + @JsOverlay + public static VueCustomElementType customElement( + String componentTag, VueJsConstructor vueJsConstructor, CustomElementOptions options) { + VueCustomElementLibInjector.ensureInjected(); + return Vue.customElementNative(componentTag, vueJsConstructor, options); + } + + // @formatter:off + public static native VueJsConstructor extend( + VueComponentOptions componentOptions); + + public static native void nextTick(JsRunnable callback); + + public static native T set(Object object, String key, T value); + + public static native boolean set(Object object, String key, boolean value); + + public static native byte set(Object object, String key, byte value); + + public static native char set(Object object, String key, char value); + + public static native float set(Object object, String key, float value); + + public static native int set(Object object, String key, int value); + + public static native short set(Object object, String key, short value); + + public static native double set(Object object, String key, double value); + + public static native void delete(Object object, String key); + + public static native void directive(String id, VueDirectiveOptions directiveOptions); + + public static native VueDirectiveOptions directive(String id); + + @JsMethod(name = "customElement") + public static native VueCustomElementType customElementNative( + String componentTag, VueJsConstructor vueJsConstructor, CustomElementOptions options); + + public static native void component(String id, + VueComponentOptions componentOptions); + + public static native void component(String id, + VueJsConstructor vueJsConstructor); + + public static native VueJsConstructor component(String id); + // @formatter:on } \ No newline at end of file diff --git a/core/src/main/java/com/axellience/vuegwt/core/client/VueCustomElementLibInjector.java b/core/src/main/java/com/axellience/vuegwt/core/client/VueCustomElementLibInjector.java index 36908a6e..65db6daf 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/client/VueCustomElementLibInjector.java +++ b/core/src/main/java/com/axellience/vuegwt/core/client/VueCustomElementLibInjector.java @@ -4,29 +4,27 @@ import elemental2.dom.HTMLScriptElement; import jsinterop.base.JsPropertyMap; -class VueCustomElementLibInjector -{ - static void ensureInjected() - { - if (isCustomElementInjected()) - return; +class VueCustomElementLibInjector { - HTMLScriptElement scriptElement = - (HTMLScriptElement) DomGlobal.document.createElement("script"); - scriptElement.text = VUE_CUSTOM_ELEMENT; - DomGlobal.document.body.appendChild(scriptElement); + static void ensureInjected() { + if (isCustomElementInjected()) { + return; } - private static boolean isCustomElementInjected() - { - return ((JsPropertyMap) DomGlobal.window).get("VueCustomElement") != null; - } + HTMLScriptElement scriptElement = + (HTMLScriptElement) DomGlobal.document.createElement("script"); + scriptElement.text = VUE_CUSTOM_ELEMENT; + DomGlobal.document.body.appendChild(scriptElement); + } + + private static boolean isCustomElementInjected() { + return ((JsPropertyMap) DomGlobal.window).get("VueCustomElement") != null; + } - /** - * vue-custom-element v1.4.2 - * (c) 2017 Karol Fabjańczuk - * Modified by Adrien Baron - * @license MIT - */ - private static String VUE_CUSTOM_ELEMENT = "!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):e.VueCustomElement=t()}(this,function(){\"use strict\";function e(e,t){return e.__proto__=t,e}function t(e,t){if(!e)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return!t||\"object\"!=typeof t&&\"function\"!=typeof t?e:t}function n(){return Reflect.construct(HTMLElement,[],this.__proto__.constructor)}function o(e){function o(){!0===i.shadow&&HTMLElement.prototype.attachShadow&&this.attachShadow({mode:\"open\"}),i.constructorCallback.call(this,this)}function r(){i.connectedCallback.call(this,this)}function c(){i.disconnectedCallback.call(this,this)}function a(e,t,n){i.attributeChangedCallback.call(this,e,t,n,this)}var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(\"undefined\"!=typeof customElements){if(f){var u=function(e){function r(e){var n;!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,r);var c=t(this,(r.__proto__||Object.getPrototypeOf(r)).call(this)),a=e?HTMLElement.call(e):c;return o.call(a),n=a,t(c,n)}return function(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(r,n),d(r,null,[{key:\"observedAttributes\",get:function(){return i.observedAttributes||[]}}]),r}();return u.prototype.connectedCallback=r,u.prototype.disconnectedCallback=c,u.prototype.attributeChangedCallback=a,customElements.define(e,u),u}var l=function(e){var t=e?HTMLElement.call(e):this;return o.call(t),t};return l.observedAttributes=i.observedAttributes||[],l.prototype=Object.create(HTMLElement.prototype,{constructor:{configurable:!0,writable:!0,value:l}}),l.prototype.connectedCallback=r,l.prototype.disconnectedCallback=c,l.prototype.attributeChangedCallback=a,customElements.define(e,l),l}}function r(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=e.length-t,o=new Array(n);n--;)o[n]=e[n+t];return o}function c(e){var t=e,n=[\"true\",\"false\"].indexOf(e)>-1,o=parseFloat(t,10),r=!isNaN(o)&&isFinite(t);return n?t=\"true\"===t:r&&(t=o),t}function a(e,t){if(e&&e.length)e.forEach(function(e){var n=h(e);-1===t.camelCase.indexOf(n)&&t.camelCase.push(n)});else if(e&&\"object\"===(void 0===e?\"undefined\":m(e)))for(var n in e){var o=h(n);-1===t.camelCase.indexOf(o)&&t.camelCase.push(o)}}function i(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=[];return r(e).forEach(function(e){if(\"#text\"===e.nodeName)e.nodeValue.trim()&&n.push(t(\"span\",e.nodeValue));else if(\"#comment\"!==e.nodeName){var o=function(e){var t={};return r(e.attributes).forEach(function(e){t[\"vue-slot\"===e.nodeName?\"slot\":e.nodeName]=e.nodeValue}),t}(e),c={attrs:o,domProps:{innerHTML:e.innerHTML}};o.slot&&(c.slot=o.slot,o.slot=void 0),n.push(t(e.tagName,c))}}),n}function u(e,t){for(var n=arguments.length,o=Array(n>2?n-2:0),r=2;r\",f.el=e.shadowRoot.children[0]):(e.innerHTML=\"
    \",f.el=e.children[0]),function(e,t){t.camelCase.forEach(function(n,o){Object.defineProperty(e,n,{get:function(){return this.__vue_custom_element__[n]},set:function(e){if(\"object\"!==(void 0===e?\"undefined\":m(e))&&\"function\"!=typeof e||!this.__vue_custom_element__)this.setAttribute(t.hyphenate[o],c(e));else{var n=t.camelCase[o];this.__vue_custom_element__[n]=e}}})})}(e,o),e.__vue_custom_element__=new t(f),r.shadow&&r.shadowCss&&e.shadowRoot){var d=document.createElement(\"style\");d.type=\"text/css\",d.appendChild(document.createTextNode(r.shadowCss)),e.shadowRoot.appendChild(d)}e.removeAttribute(\"vce-cloak\"),e.setAttribute(\"vce-ready\",\"\"),u(e,\"vce-ready\")}}function s(e){e.customElement=function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=function(e){var t={camelCase:[],hyphenate:[]},n=e.options;return n?(n.mixins&&n.mixins.forEach(function(e){a(e.props,t)}),a(n.props,t),t.camelCase.forEach(function(e){t.hyphenate.push(b(e))}),t):t}(n);return o(t,{constructorCallback:function(e){\"function\"==typeof r.constructorCallback&&r.constructorCallback.call(this,e)},connectedCallback:function(t){this.__detached__||l(this,e,n,i,r),\"function\"==typeof r.connectedCallback&&r.connectedCallback.call(this,t),this.__detached__=!1},disconnectedCallback:function(e){var t=this;this.__detached__=!0,\"function\"==typeof r.disconnectedCallback&&r.disconnectedCallback.call(this,e),setTimeout(function(){t.__detached__&&t.__vue_custom_element__&&t.__vue_custom_element__.$destroy(!0)},r.destroyTimeout||3e3)},attributeChangedCallback:function(e,t,n,o){if(this.__vue_custom_element__&&void 0!==n){var a=h(e);\"function\"==typeof r.attributeChangedCallback&&r.attributeChangedCallback.call(this,o,e,t,n),this.__vue_custom_element__[a]=c(n)}},observedAttributes:i.hyphenate,shadow:!!r.shadow&&!!HTMLElement.prototype.attachShadow})}}Object.setPrototypeOf=Object.setPrototypeOf||e;e.bind(Object);var f=\"undefined\"!=typeof Symbol&&\"undefined\"!=typeof Reflect,d=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(\"undefined\"!=typeof customElements){if(f){var u=function(e){function r(e){var n;!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,r);var c=t(this,(r.__proto__||Object.getPrototypeOf(r)).call(this)),a=e?HTMLElement.call(e):c;return o.call(a),n=a,t(c,n)}return function(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function, not \"+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(r,n),d(r,null,[{key:\"observedAttributes\",get:function(){return i.observedAttributes||[]}}]),r}();return u.prototype.connectedCallback=r,u.prototype.disconnectedCallback=c,u.prototype.attributeChangedCallback=a,customElements.define(e,u),u}var l=function(e){var t=e?HTMLElement.call(e):this;return o.call(t),t};return l.observedAttributes=i.observedAttributes||[],l.prototype=Object.create(HTMLElement.prototype,{constructor:{configurable:!0,writable:!0,value:l}}),l.prototype.connectedCallback=r,l.prototype.disconnectedCallback=c,l.prototype.attributeChangedCallback=a,customElements.define(e,l),l}}function r(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=e.length-t,o=new Array(n);n--;)o[n]=e[n+t];return o}function c(e){var t=e,n=[\"true\",\"false\"].indexOf(e)>-1,o=parseFloat(t,10),r=!isNaN(o)&&isFinite(t);return n?t=\"true\"===t:r&&(t=o),t}function a(e,t){if(e&&e.length)e.forEach(function(e){var n=h(e);-1===t.camelCase.indexOf(n)&&t.camelCase.push(n)});else if(e&&\"object\"===(void 0===e?\"undefined\":m(e)))for(var n in e){var o=h(n);-1===t.camelCase.indexOf(o)&&t.camelCase.push(o)}}function i(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments[1],n=[];return r(e).forEach(function(e){if(\"#text\"===e.nodeName)e.nodeValue.trim()&&n.push(t(\"span\",e.nodeValue));else if(\"#comment\"!==e.nodeName){var o=function(e){var t={};return r(e.attributes).forEach(function(e){t[\"vue-slot\"===e.nodeName?\"slot\":e.nodeName]=e.nodeValue}),t}(e),c={attrs:o,domProps:{innerHTML:e.innerHTML}};o.slot&&(c.slot=o.slot,o.slot=void 0),n.push(t(e.tagName,c))}}),n}function u(e,t){for(var n=arguments.length,o=Array(n>2?n-2:0),r=2;r\",f.el=e.shadowRoot.children[0]):(e.innerHTML=\"
    \",f.el=e.children[0]),function(e,t){t.camelCase.forEach(function(n,o){Object.defineProperty(e,n,{get:function(){return this.__vue_custom_element__[n]},set:function(e){if(\"object\"!==(void 0===e?\"undefined\":m(e))&&\"function\"!=typeof e||!this.__vue_custom_element__)this.setAttribute(t.hyphenate[o],c(e));else{var n=t.camelCase[o];this.__vue_custom_element__[n]=e}}})})}(e,o),e.__vue_custom_element__=new t(f),r.shadow&&r.shadowCss&&e.shadowRoot){var d=document.createElement(\"style\");d.type=\"text/css\",d.appendChild(document.createTextNode(r.shadowCss)),e.shadowRoot.appendChild(d)}e.removeAttribute(\"vce-cloak\"),e.setAttribute(\"vce-ready\",\"\"),u(e,\"vce-ready\")}}function s(e){e.customElement=function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=function(e){var t={camelCase:[],hyphenate:[]},n=e.options;return n?(n.mixins&&n.mixins.forEach(function(e){a(e.props,t)}),a(n.props,t),t.camelCase.forEach(function(e){t.hyphenate.push(b(e))}),t):t}(n);return o(t,{constructorCallback:function(e){\"function\"==typeof r.constructorCallback&&r.constructorCallback.call(this,e)},connectedCallback:function(t){this.__detached__||l(this,e,n,i,r),\"function\"==typeof r.connectedCallback&&r.connectedCallback.call(this,t),this.__detached__=!1},disconnectedCallback:function(e){var t=this;this.__detached__=!0,\"function\"==typeof r.disconnectedCallback&&r.disconnectedCallback.call(this,e),setTimeout(function(){t.__detached__&&t.__vue_custom_element__&&t.__vue_custom_element__.$destroy(!0)},r.destroyTimeout||3e3)},attributeChangedCallback:function(e,t,n,o){if(this.__vue_custom_element__&&void 0!==n){var a=h(e);\"function\"==typeof r.attributeChangedCallback&&r.attributeChangedCallback.call(this,o,e,t,n),this.__vue_custom_element__[a]=c(n)}},observedAttributes:i.hyphenate,shadow:!!r.shadow&&!!HTMLElement.prototype.attachShadow})}}Object.setPrototypeOf=Object.setPrototypeOf||e;e.bind(Object);var f=\"undefined\"!=typeof Symbol&&\"undefined\"!=typeof Reflect,d=function(){function e(e,t){for(var n=0;n onReadyCallbacks = new LinkedList<>(); - - private static final Map scopedCss = new HashMap<>(); - - /** - * Inject scripts necessary for Vue GWT to work. - * Also inject Vue.js library. - */ - @JsIgnore - public static void init() - { - if (isDevMode()) - VueLibDevInjector.ensureInjected(); - else - VueLibInjector.ensureInjected(); - - // Init VueGWT - VueGWT.initWithoutVueLib(); - } - - private static boolean isDevMode() - { - return "on".equals(System.getProperty("superdevmode", "off")) || "development".equals(System - .getProperty("vuegwt.environment", "production")); - } - - /** - * Inject scripts necessary for Vue GWT to work - * Requires Vue to be defined in Window. - */ - @JsIgnore - public static void initWithoutVueLib() - { - if (!isVueLibInjected()) - throw new RuntimeException( - "Couldn't find Vue.js on init. Either include it Vue.js in your index.html or call VueGWT.init() instead of initWithoutVueLib."); - - // Register custom observers for Collection and Maps - VueGWTObserverManager.get().registerVueGWTObserver(new CollectionObserver()); - VueGWTObserverManager.get().registerVueGWTObserver(new MapObserver()); - - isReady = true; - - // Call on ready callbacks - for (Runnable onReadyCbk : onReadyCallbacks) - onReadyCbk.run(); - onReadyCallbacks.clear(); - - injectScopedCss(); - } - - private static void injectScopedCss() { - if (scopedCss.isEmpty()) return; - String all = ""; - for (Entry i : scopedCss.entrySet()) { - all += i.getValue(); - } - injectCss(all); - } - - @JsIgnore - private static void injectCss(String css) { - if (css == null || css.isEmpty()) return; - HTMLStyleElement styleElement = (HTMLStyleElement) DomGlobal.document.createElement("style"); - styleElement.type = "text/css"; - styleElement.textContent = css; - DomGlobal.document.head.appendChild(styleElement); - } - - /** - * Create a {@link Vue} instance for the given Vue Component Class. - * You can then call $mount on it to mount the instance. - * @param isVueComponentClass The Class of the Component to create - * @param The type of the {@link IsVueComponent} - * @return The created instance of our Component (not yet mounted) - */ - @JsIgnore - public static T createInstance(Class isVueComponentClass) - { - return getVueComponentFactory(isVueComponentClass).create(); - } - - /** - * Return the {@link VueComponentFactory} for the given {@link IsVueComponent} class. - * @param isVueComponentClass The {@link IsVueComponent} class - * @param The type of the {@link IsVueComponent} - * @return A {@link VueComponentFactory} you can use to instantiate components - */ - @JsIgnore - public static VueComponentFactory getVueComponentFactory(Class isVueComponentClass) - { - if (JsObject.class.equals(isVueComponentClass)) - { - throw new RuntimeException( - "You can't use the .class of a JsComponent to instantiate it. Please use MyComponentFactory.get() instead."); - } - return getVueComponentFactory(isVueComponentClass.getCanonicalName()); - } - - /** - * Return the {@link VueComponentFactory} for the given {@link IsVueComponent} fully qualified name. - * @param componentQualifiedName The fully qualified name of the {@link IsVueComponent} class - * @param The type of the {@link IsVueComponent} - * @return A {@link VueComponentFactory} you can use to instantiate components - */ - public static VueComponentFactory getVueComponentFactory(String componentQualifiedName) - { - ComponentExposedTypeConstructorFn javaConstructor = - getComponentExposedTypeConstructorFn(componentQualifiedName); - if (javaConstructor != null) - return javaConstructor.getVueComponentFactory(); - - throw new RuntimeException("Couldn't find VueComponentFactory for Component: " - + componentQualifiedName - + ". Make sure that annotation are being processed, and that you added the -generateJsInteropExports flag to GWT. You can also try a \"mvn clean\" on your maven project."); - } - - /** - * Return the {@link VueJsConstructor} for the given {@link IsVueComponent} class. - * @param isVueComponentClass The {@link IsVueComponent} class - * @param The type of the {@link IsVueComponent} - * @return A {@link VueJsConstructor} you can use to instantiate components - */ - @JsIgnore - public static VueJsConstructor getJsConstructor( - Class isVueComponentClass) - { - return getVueComponentFactory(isVueComponentClass).getJsConstructor(); - } - - /** - * Return the {@link VueJsConstructor} for the given {@link IsVueComponent} fully qualified name. - * @param qualifiedName The fully qualified name of the {@link IsVueComponent} class - * @param The type of the {@link IsVueComponent} - * @return A {@link VueJsConstructor} you can use to instantiate components - */ - public static VueJsConstructor getJsConstructor( - String qualifiedName) - { - return (VueJsConstructor) getVueComponentFactory(qualifiedName).getJsConstructor(); - } - - /** - * Return the Java Constructor of our {@link IsVueComponent} Java Class. - * This Constructor can be used to get the prototype of our Java Class and get the - * VueComponent methods from it. - * @param isVueComponentClass The {@link IsVueComponent} we want the constructor of - * @param The type of the {@link IsVueComponent} - * @return The Java constructor of our {@link IsVueComponent} - */ - @JsIgnore - public static ComponentExposedTypeConstructorFn getComponentExposedTypeConstructorFn( - Class isVueComponentClass) - { - return getComponentExposedTypeConstructorFn(isVueComponentClass.getCanonicalName()); - } - - /** - * Return the Java Constructor of our {@link IsVueComponent} ExposedType Java Class. - * This Constructor can be used to get the prototype of our Java Class and get the - * VueComponent methods from it. - * @param componentQualifiedName The fully qualified name of the {@link IsVueComponent} class - * @param The type of the {@link IsVueComponent} - * @return The Java constructor of our {@link IsVueComponent} - */ - public static ComponentExposedTypeConstructorFn getComponentExposedTypeConstructorFn( - String componentQualifiedName) - { - return (ComponentExposedTypeConstructorFn) VueGWTWindow.VueGWTExposedTypesRepository.get( - componentQualifiedName.replaceAll("\\.", "_")); - } - - @JsIgnore - public static void registerScopedCss(String qualifiedName, String css) { - if (css == null || css.isEmpty()) return; - scopedCss.put(qualifiedName, css); - } - - /** - * Ask to be warned when Vue GWT is ready. - * If Vue GWT is ready, the callback is called immediately. - * @param callback The callback to call when Vue GWT is ready. - */ - @JsIgnore - public static void onReady(Runnable callback) - { - if (isReady) - { - callback.run(); - return; - } - - onReadyCallbacks.push(callback); - } - - static boolean isVueLibInjected() - { - return ((JsPropertyMap) DomGlobal.window).get("Vue") != null; - } - - @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "window") - private static class VueGWTWindow - { - public static JsPropertyMap> - VueGWTExposedTypesRepository; - } +public class VueGWT { + + private static boolean isReady = false; + private static LinkedList onReadyCallbacks = new LinkedList<>(); + + private static final Map scopedCss = new HashMap<>(); + + /** + * Inject scripts necessary for Vue GWT to work. Also inject Vue.js library. + */ + @JsIgnore + public static void init() { + if (isDevMode()) { + VueLibDevInjector.ensureInjected(); + } else { + VueLibInjector.ensureInjected(); + } + + // Init VueGWT + VueGWT.initWithoutVueLib(); + } + + private static boolean isDevMode() { + return "on".equals(System.getProperty("superdevmode", "off")) || "development".equals(System + .getProperty("vuegwt.environment", "production")); + } + + /** + * Inject scripts necessary for Vue GWT to work Requires Vue to be defined in Window. + */ + @JsIgnore + public static void initWithoutVueLib() { + if (!isVueLibInjected()) { + throw new RuntimeException( + "Couldn't find Vue.js on init. Either include it Vue.js in your index.html or call VueGWT.init() instead of initWithoutVueLib."); + } + + // Register custom observers for Collection and Maps + VueGWTObserverManager.get().registerVueGWTObserver(new CollectionObserver()); + VueGWTObserverManager.get().registerVueGWTObserver(new MapObserver()); + + isReady = true; + + // Call on ready callbacks + for (Runnable onReadyCbk : onReadyCallbacks) { + onReadyCbk.run(); + } + onReadyCallbacks.clear(); + + injectScopedCss(); + } + + private static void injectScopedCss() { + if (scopedCss.isEmpty()) { + return; + } + String all = ""; + for (Entry i : scopedCss.entrySet()) { + all += i.getValue(); + } + injectCss(all); + } + + @JsIgnore + private static void injectCss(String css) { + if (css == null || css.isEmpty()) { + return; + } + HTMLStyleElement styleElement = (HTMLStyleElement) DomGlobal.document.createElement("style"); + styleElement.type = "text/css"; + styleElement.textContent = css; + DomGlobal.document.head.appendChild(styleElement); + } + + /** + * Create a {@link Vue} instance for the given Vue Component Class. You can then call $mount on it + * to mount the instance. + * + * @param isVueComponentClass The Class of the Component to create + * @param The type of the {@link IsVueComponent} + * @return The created instance of our Component (not yet mounted) + */ + @JsIgnore + public static T createInstance(Class isVueComponentClass) { + return getVueComponentFactory(isVueComponentClass).create(); + } + + /** + * Return the {@link VueComponentFactory} for the given {@link IsVueComponent} class. + * + * @param isVueComponentClass The {@link IsVueComponent} class + * @param The type of the {@link IsVueComponent} + * @return A {@link VueComponentFactory} you can use to instantiate components + */ + @JsIgnore + public static VueComponentFactory getVueComponentFactory( + Class isVueComponentClass) { + if (JsObject.class.equals(isVueComponentClass)) { + throw new RuntimeException( + "You can't use the .class of a JsComponent to instantiate it. Please use MyComponentFactory.get() instead."); + } + return getVueComponentFactory(isVueComponentClass.getCanonicalName()); + } + + /** + * Return the {@link VueComponentFactory} for the given {@link IsVueComponent} fully qualified + * name. + * + * @param componentQualifiedName The fully qualified name of the {@link IsVueComponent} class + * @param The type of the {@link IsVueComponent} + * @return A {@link VueComponentFactory} you can use to instantiate components + */ + public static VueComponentFactory getVueComponentFactory( + String componentQualifiedName) { + ComponentExposedTypeConstructorFn javaConstructor = + getComponentExposedTypeConstructorFn(componentQualifiedName); + if (javaConstructor != null) { + return javaConstructor.getVueComponentFactory(); + } + + throw new RuntimeException("Couldn't find VueComponentFactory for Component: " + + componentQualifiedName + + ". Make sure that annotation are being processed, and that you added the -generateJsInteropExports flag to GWT. You can also try a \"mvn clean\" on your maven project."); + } + + /** + * Return the {@link VueJsConstructor} for the given {@link IsVueComponent} class. + * + * @param isVueComponentClass The {@link IsVueComponent} class + * @param The type of the {@link IsVueComponent} + * @return A {@link VueJsConstructor} you can use to instantiate components + */ + @JsIgnore + public static VueJsConstructor getJsConstructor( + Class isVueComponentClass) { + return getVueComponentFactory(isVueComponentClass).getJsConstructor(); + } + + /** + * Return the {@link VueJsConstructor} for the given {@link IsVueComponent} fully qualified name. + * + * @param qualifiedName The fully qualified name of the {@link IsVueComponent} class + * @param The type of the {@link IsVueComponent} + * @return A {@link VueJsConstructor} you can use to instantiate components + */ + public static VueJsConstructor getJsConstructor( + String qualifiedName) { + return (VueJsConstructor) getVueComponentFactory(qualifiedName).getJsConstructor(); + } + + /** + * Return the Java Constructor of our {@link IsVueComponent} Java Class. This Constructor can be + * used to get the prototype of our Java Class and get the VueComponent methods from it. + * + * @param isVueComponentClass The {@link IsVueComponent} we want the constructor of + * @param The type of the {@link IsVueComponent} + * @return The Java constructor of our {@link IsVueComponent} + */ + @JsIgnore + public static ComponentExposedTypeConstructorFn getComponentExposedTypeConstructorFn( + Class isVueComponentClass) { + return getComponentExposedTypeConstructorFn(isVueComponentClass.getCanonicalName()); + } + + /** + * Return the Java Constructor of our {@link IsVueComponent} ExposedType Java Class. This + * Constructor can be used to get the prototype of our Java Class and get the VueComponent methods + * from it. + * + * @param componentQualifiedName The fully qualified name of the {@link IsVueComponent} class + * @param The type of the {@link IsVueComponent} + * @return The Java constructor of our {@link IsVueComponent} + */ + public static ComponentExposedTypeConstructorFn getComponentExposedTypeConstructorFn( + String componentQualifiedName) { + return (ComponentExposedTypeConstructorFn) VueGWTWindow.VueGWTExposedTypesRepository.get( + componentQualifiedName.replaceAll("\\.", "_")); + } + + @JsIgnore + public static void registerScopedCss(String qualifiedName, String css) { + if (css == null || css.isEmpty()) { + return; + } + scopedCss.put(qualifiedName, css); + } + + /** + * Ask to be warned when Vue GWT is ready. If Vue GWT is ready, the callback is called + * immediately. + * + * @param callback The callback to call when Vue GWT is ready. + */ + @JsIgnore + public static void onReady(Runnable callback) { + if (isReady) { + callback.run(); + return; + } + + onReadyCallbacks.push(callback); + } + + static boolean isVueLibInjected() { + return ((JsPropertyMap) DomGlobal.window).get("Vue") != null; + } + + @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "window") + private static class VueGWTWindow { + + public static JsPropertyMap> + VueGWTExposedTypesRepository; + } } diff --git a/core/src/main/java/com/axellience/vuegwt/core/client/VueLibDevInjector.java b/core/src/main/java/com/axellience/vuegwt/core/client/VueLibDevInjector.java index 29b507b2..88c3e7f9 100644 --- a/core/src/main/java/com/axellience/vuegwt/core/client/VueLibDevInjector.java +++ b/core/src/main/java/com/axellience/vuegwt/core/client/VueLibDevInjector.java @@ -1,40 +1,43 @@ package com.axellience.vuegwt.core.client; +import static com.axellience.vuegwt.core.client.VueGWT.isVueLibInjected; + import elemental2.dom.DomGlobal; import elemental2.dom.HTMLScriptElement; -import static com.axellience.vuegwt.core.client.VueGWT.isVueLibInjected; - /** -This class is generated by utils/vue-runtime/vue-dev-runtime.js -*/ -class VueLibDevInjector -{ - static void ensureInjected() - { - if (isVueLibInjected()) - return; + * This class is generated by utils/vue-runtime/vue-dev-runtime.js + */ +class VueLibDevInjector { - HTMLScriptElement scriptElement = - (HTMLScriptElement) DomGlobal.document.createElement("script"); - scriptElement.text = VUE_DEV_RUNTIME; - DomGlobal.document.body.appendChild(scriptElement); + static void ensureInjected() { + if (isVueLibInjected()) { + return; } - /*! - * Vue.js v2.5.16 - * (c) 2014-2018 Evan You - * Released under the MIT License. - */ - private static String VUE_DEV_RUNTIME; + HTMLScriptElement scriptElement = + (HTMLScriptElement) DomGlobal.document.createElement("script"); + scriptElement.text = VUE_DEV_RUNTIME; + DomGlobal.document.body.appendChild(scriptElement); + } - static - { - StringBuilder builder = new StringBuilder(); -builder.append("/*!\n * Vue.js v2.5.16\n * (c) 2014-2018 Evan You\n * Released under the MIT License.\n */\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global.Vue = factory());\n}(this, (function () { 'use strict';\n\n/* */\n\nvar emptyObject = Object.freeze({});\n\n// these helpers produces better vm code in JS engines due to their\n// explicitness and function inlining\nfunction isUndef (v) {\n return v === undefined || v === null\n}\n\nfunction isDef (v) {\n return v !== undefined && v !== null\n}\n\nfunction isTrue (v) {\n return v === true\n}\n\nfunction isFalse (v) {\n return v === false\n}\n\n/**\n * Check if value is primitive\n */\nfunction isPrimitive (value) {\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n // $flow-disable-line\n typeof value === 'symbol' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Quick object check - this is primarily used to tell\n * Objects from primitive values when we know the value\n * is a JSON-compliant type.\n */\nfunction isObject (obj) {\n return obj !== null && typeof obj === 'object'\n}\n\n/**\n * Get the raw type string of a value e.g. [object Object]\n */\nvar _toString = Object.prototype.toString;\n\nfunction toRawType (value) {\n return _toString.call(value).slice(8, -1)\n}\n\n/**\n * Strict object type check. Only returns true\n * for plain JavaScript objects.\n */\nfunction isPlainObject (obj) {\n return _toString.call(obj) === '[object Object]'\n}\n\nfunction isRegExp (v) {\n return _toString.call(v) === '[object RegExp]'\n}\n\n/**\n * Check if val is a valid array index.\n */\nfunction isValidArrayIndex (val) {\n var n = parseFloat(String(val));\n return n >= 0 && Math.floor(n) === n && isFinite(val)\n}\n\n/**\n * Convert a value to a string that is actually rendered.\n */\nfunction toString (val) {\n return val == null\n ? ''\n : typeof val === 'object'\n ? JSON.stringify(val, null, 2)\n : String(val)\n}\n\n/**\n * Convert a input value to a number for persistence.\n * If the conversion fails, return original string.\n */\nfunction toNumber (val) {\n var n = parseFloat(val);\n return isNaN(n) ? val : n\n}\n\n/**\n * Make a map and return a function for checking if a key\n * is in that map.\n */\nfunction makeMap (\n str,\n expectsLowerCase\n) {\n var map = Object.create(null);\n var list = str.split(',');\n for (var i = 0; i < list.length; i++) {\n map[list[i]] = true;\n }\n return expectsLowerCase\n ? function (val) { return map[val.toLowerCase()]; }\n : function (val) { return map[val]; }\n}\n\n/**\n * Check if a tag is a built-in tag.\n */\nvar isBuiltInTag = makeMap('slot,component', true);\n\n/**\n * Check if a attribute is a reserved attribute.\n */\nvar isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');\n\n/**\n * Remove an item from an array\n */\nfunction remove (arr, item) {\n if (arr.length) {\n var index = arr.indexOf(item);\n if (index > -1) {\n return arr.splice(index, 1)\n }\n }\n}\n\n/**\n * Check whether the object has the property.\n */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nfunction hasOwn (obj, key) {\n return hasOwnProperty.call(obj, key)\n}\n\n/**\n * Create a cached version of a pure function.\n */\nfunction cached (fn) {\n var cache = Object.create(null);\n return (function cachedFn (str) {\n var hit = cache[str];\n return hit || (cache[str] = fn(str))\n })\n}\n\n/**\n * Camelize a hyphen-delimited string.\n */\nvar camelizeRE = /-(\\w)/g;\nvar camelize = cached(function (str) {\n return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })\n});\n\n/**\n * Capitalize a string.\n */\nvar capitalize = cached(function (str) {\n return str.charAt(0).toUpperCase() + str.slice(1)\n});\n\n/**\n * Hyphenate a camelCase string.\n */\nvar hyphenateRE = /\\B([A-Z])/g;\nvar hyphenate = cached(function (str) {\n return str.replace(hyphenateRE, '-$1').toLowerCase()\n});\n\n/**\n * Simple bind polyfill for environments that do not support it... e.g.\n * PhantomJS 1.x. Technically we don't need this anymore since native bind is\n * now more performant in most browsers, but removing it would be breaking for\n * code that was able to run in PhantomJS 1.x, so this must be kept for\n * backwards compatibility.\n */\n\n/* istanbul ignore next */\nfunction polyfillBind (fn, ctx) {\n function boundFn (a) {\n var l = arguments.length;\n return l\n ? l > 1\n ? fn.apply(ctx, arguments)\n : fn.call(ctx, a)\n : fn.call(ctx)\n }\n\n boundFn._length = fn.length;\n return boundFn\n}\n\nfunction nativeBind (fn, ctx) {\n return fn.bind(ctx)\n}\n\nvar bind = Function.prototype.bind\n ? nativeBind\n : polyfillBind;\n\n/**\n * Convert an Array-like object to a real Array.\n */\nfunction toArray (list, start) {\n start = start || 0;\n var i = list.length - start;\n var ret = new Array(i);\n while (i--) {\n ret[i] = list[i + start];\n }\n return ret\n}\n\n/**\n * Mix properties into target object.\n */\nfunction extend (to, _from) {\n for (var key in _from) {\n to[key] = _from[key];\n }\n return to\n}\n\n/**\n * Merge an Array of Objects into a single Object.\n */\nfunction toObject (arr) {\n var res = {};\n for (var i = 0; i < arr.length; i++) {\n if (arr[i]) {\n extend(res, arr[i]);\n }\n }\n return res\n}\n\n/**\n * Perform no operation.\n * Stubbing args to make Flow happy without leaving useless transpiled code\n * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/)\n */\nfunction noop (a, b, c) {}\n\n/**\n * Always return false.\n */\nvar no = function (a, b, c) { return false; };\n\n/**\n * Return same value\n */\nvar identity = function (_) { return _; };\n\n/**\n * Generate a static keys string from compiler modules.\n */\n\n\n/**\n * Check if two values are loosely equal - that is,\n * if they are plain objects, do they have the same shape?\n */\nfunction looseEqual (a, b) {\n if (a === b) { return true }\n var isObjectA = isObject(a);\n var isObjectB = isObject(b);\n if (isObjectA && isObjectB) {\n try {\n var isArrayA = Array.isArray(a);\n var isArrayB = Array.isArray(b);\n if (isArrayA && isArrayB) {\n return a.length === b.length && a.every(function (e, i) {\n return looseEqual(e, b[i])\n })\n } else if (!isArrayA && !isArrayB) {\n var keysA = Object.keys(a);\n var keysB = Object.keys(b);\n return keysA.length === keysB.length && keysA.every(function (key) {\n return looseEqual(a[key], b[key])\n })\n } else {\n /* istanbul ignore next */\n return false\n }\n } catch (e) {\n /* istanbul ignore next */\n return false\n }\n } else if (!isObjectA && !isObjectB) {\n return String(a) === String(b)\n } else {\n return false\n }\n}\n\nfunction looseIndexOf (arr, val) {\n for (var i = 0; i < arr.length; i++) {\n if (looseEqual(arr[i], val)) { return i }\n }\n return -1\n}\n\n/**\n * Ensure a function is called only once.\n */\nfunction once (fn) {\n var called = false;\n return function () {\n if (!called) {\n called = true;\n fn.apply(this, arguments);\n }\n }\n}\n\nvar SSR_ATTR = 'data-server-rendered';\n\nvar ASSET_TYPES = [\n 'component',\n 'directive',\n 'filter'\n];\n\nvar LIFECYCLE_HOOKS = [\n 'beforeCreate',\n 'created',\n 'beforeMount',\n 'mounted',\n 'beforeUpdate',\n 'updated',\n 'beforeDestroy',\n 'destroyed',\n 'activated',\n 'deactivated',\n 'errorCaptured'\n];\n\n/* */\n\nvar config = ({\n /**\n * Option merge strategies (used in core/util/options)\n */\n // $flow-disable-line\n optionMergeStrategies: Object.create(null),\n\n /**\n * Whether to suppress warnings.\n */\n silent: false,\n\n /**\n * Show production mode tip message on boot?\n */\n productionTip: \"development\" !== 'production',\n\n /**\n * Whether to enable devtools\n */\n devtools: \"development\" !== 'production',\n\n /**\n * Whether to record perf\n */\n performance: false,\n\n /**\n * Error handler for watcher errors\n */\n errorHandler: null,\n\n /**\n * Warn handler for watcher warns\n */\n warnHandler: null,\n\n /**\n * Ignore certain custom elements\n */\n ignoredElements: [],\n\n /**\n * Custom user key aliases for v-on\n */\n // $flow-disable-line\n keyCodes: Object.create(null),\n\n /**\n * Check if a tag is reserved so that it cannot be registered as a\n * component. This is platform-dependent and may be overwritten.\n */\n isReservedTag: no,\n\n /**\n * Check if an attribute is reserved so that it cannot be used as a component\n * prop. This is platform-dependent and may be overwritten.\n */\n isReservedAttr: no,\n\n /**\n * Check if a tag is an unknown element.\n * Platform-dependent.\n */\n isUnknownElement: no,\n\n /**\n * Get the namespace of an element\n */\n getTagNamespace: noop,\n\n /**\n * Parse the real tag name for the specific platform.\n */\n parsePlatformTagName: identity,\n\n /**\n * Check if an attribute must be bound using property, e.g. value\n * Platform-dependent.\n */\n mustUseProp: no,\n\n /**\n * Exposed for legacy reasons\n */\n _lifecycleHooks: LIFECYCLE_HOOKS\n})\n\n/* */\n\n/**\n * Check if a string starts with $ or _\n */\nfunction isReserved (str) {\n var c = (str + '').charCodeAt(0);\n return c === 0x24 || c === 0x5F\n}\n\n/**\n * Define a property.\n */\nfunction def (obj, key, val, enumerable) {\n Object.defineProperty(obj, key, {\n value: val,\n enumerable: !!enumerable,\n writable: true,\n configurable: true\n });\n}\n\n/**\n * Parse simple path.\n */\nvar bailRE = /[^\\w.$]/;\nfunction parsePath (path) {\n if (bailRE.test(path)) {\n return\n }\n var segments = path.split('.');\n return function (obj) {\n for (var i = 0; i < segments.length; i++) {\n if (!obj) { return }\n obj = obj[segments[i]];\n }\n return obj\n }\n}\n\n/* */\n\n// can we use __proto__?\nvar hasProto = '__proto__' in {};\n\n// Browser environment sniffing\nvar inBrowser = typeof window !== 'undefined';\nvar inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform;\nvar weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();\nvar UA = inBrowser && window.navigator.userAgent.toLowerCase();\nvar isIE = UA && /msie|trident/.test(UA);\nvar isIE9 = UA && UA.indexOf('msie 9.0') > 0;\nvar isEdge = UA && UA.indexOf('edge/') > 0;\nvar isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android');\nvar isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios');\nvar isChrome = UA && /chrome\\/\\d+/.test(UA) && !isEdge;\n\n// Firefox has a \"watch\" function on Object.prototype...\nvar nativeWatch = ({}).watch;\n\nvar supportsPassive = false;\nif (inBrowser) {\n try {\n var opts = {};\n Object.defineProperty(opts, 'passive', ({\n get: function get () {\n /* istanbul ignore next */\n supportsPassive = true;\n }\n })); // https://github.com/facebook/flow/issues/285\n window.addEventListener('test-passive', null, opts);\n } catch (e) {}\n}\n\n// this needs to be lazy-evaled because vue may be required before\n// vue-server-renderer can set VUE_ENV\nvar _isServer;\nvar isServerRendering = function () {\n if (_isServer === undefined) {\n /* istanbul ignore if */\n if (!inBrowser && !inWeex && typeof global !== 'undefined') {\n // detect presence of vue-server-renderer and avoid\n // Webpack shimming the process\n _isServer = global['process'].env.VUE_ENV === 'server';\n } else {\n _isServer = false;\n }\n }\n return _isServer\n};\n\n// detect devtools\nvar devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;\n\n/* istanbul ignore next */\nfunction isNative (Ctor) {\n return typeof Ctor === 'function' && /native code/.test(Ctor.toString())\n}\n\nvar hasSymbol =\n typeof Symbol !== 'undefined' && isNative(Symbol) &&\n typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);\n\nvar _Set;\n/* istanbul ignore if */ // $flow-disable-line\nif (typeof Set !== 'undefined' && isNative(Set)) {\n // use native Set when available.\n _Set = Set;\n} else {\n // a non-standard Set polyfill that only works with primitive keys.\n _Set = (function () {\n function Set () {\n this.set = Object.create(null);\n }\n Set.prototype.has = function has (key) {\n return this.set[key] === true\n };\n Set.prototype.add = function add (key) {\n this.set[key] = true;\n };\n Set.prototype.clear = function clear () {\n this.set = Object.create(null);\n };\n\n return Set;\n }());\n}\n\n/* */\n\nvar warn = noop;\nvar tip = noop;\nvar generateComponentTrace = (noop); // work around flow check\nvar formatComponentName = (noop);\n\n{\n var hasConsole = typeof console !== 'undefined';\n var classifyRE = /(?:^|[-_])(\\w)/g;\n var classify = function (str) { return str\n .replace(classifyRE, function (c) { return c.toUpperCase(); })\n .replace(/[-_]/g, ''); };\n\n warn = function (msg, vm) {\n var trace = vm ? generateComponentTrace(vm) : '';\n\n if (config.warnHandler) {\n config.warnHandler.call(null, msg, vm, trace);\n } else if (hasConsole && (!config.silent)) {\n console.error((\"[Vue warn]: \" + msg + trace));\n }\n };\n\n tip = function (msg, vm) {\n if (hasConsole && (!config.silent)) {\n console.warn(\"[Vue tip]: \" + msg + (\n vm ? generateComponentTrace(vm) : ''\n ));\n }\n };\n\n formatComponentName = function (vm, includeFile) {\n if (vm.$root === vm) {\n return ''\n }\n var options = typeof vm === 'function' && vm.cid != null\n ? vm.options\n : vm._isVue\n ? vm.$options || vm.constructor.options\n : vm || {};\n var name = options.name || options._componentTag;\n var file = options.__file;\n if (!name && file) {\n var match = file.match(/([^/\\\\]+)\\.vue$/);\n name = match && match[1];\n }\n\n return (\n (name ? (\"<\" + (classify(name)) + \">\") : \"\") +\n (file && includeFile !== false ? (\" at \" + file) : '')\n )\n };\n\n var repeat = function (str, n) {\n var res = '';\n while (n) {\n if (n % 2 === 1) { res += str; }\n if (n > 1) { str += str; }\n n >>= 1;\n }\n return res\n };\n\n generateComponentTrace = function (vm) {\n if (vm._isVue && vm.$parent) {\n var tree = [];\n var currentRecursiveSequence = 0;\n while (vm) {\n if (tree.length > 0) {\n var last = tree[tree.length - 1];\n if (last.constructor === vm.constructor) {\n currentRecursiveSequence++;\n vm = vm.$parent;\n continue\n } else if (currentRecursiveSequence > 0) {\n tree[tree.length - 1] = [last, currentRecursiveSequence];\n currentRecursiveSequence = 0;\n }\n }\n tree.push(vm);\n vm = vm.$parent;\n }\n return '\\n\\nfound in\\n\\n' + tree\n .map(function (vm, i) { return (\"\" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm)\n ? ((formatComponentName(vm[0])) + \"... (\" + (vm[1]) + \" recursive calls)\")\n : formatComponentName(vm))); })\n .join('\\n')\n } else {\n return (\"\\n\\n(found in \" + (formatComponentName(vm)) + \")\")\n }\n };\n}\n\n/* */\n\n\nvar uid = 0;\n\n/**\n * A dep is an observable that can have multiple\n * directives subscribing to it.\n */\nvar Dep = function Dep () {\n this.id = uid++;\n this.subs = [];\n};\n\nDep.prototype.addSub = function addSub (sub) {\n this.subs.push(sub);\n};\n\nDep.prototype.removeSub = function removeSub (sub) {\n remove(this.subs, sub);\n};\n\nDep.prototype.depend = function depend () {\n if (Dep.target) {\n Dep.target.addDep(this);\n }\n};\n\nDep.prototype.notify = function notify () {\n // stabilize the subscriber list first\n var subs = this.subs.slice();\n for (var i = 0, l = subs.length; i < l; i++) {\n subs[i].update();\n }\n};\n\n// the current target watcher being evaluated.\n// this is globally unique because there could be only one\n// watcher being evaluated at any time.\nDep.target = null;\nvar targetStack = [];\n\nfunction pushTarget (_target) {\n if (Dep.target) { targetStack.push(Dep.target); }\n Dep.target = _target;\n}\n\nfunction popTarget () {\n Dep.target = targetStack.pop();\n}\n\n/* */\n\nvar VNode = function VNode (\n tag,\n data,\n children,\n text,\n elm,\n context,\n componentOptions,\n asyncFactory\n) {\n this.tag = tag;\n this.data = data;\n this.children = children;\n this.text = text;\n this.elm = elm;\n this.ns = undefined;\n this.context = context;\n this.fnContext = undefined;\n this.fnOptions = undefined;\n this.fnScopeId = undefined;\n this.key = data && data.key;\n this.componentOptions = componentOptions;\n this.componentInstance = undefined;\n this.parent = undefined;\n this.raw = false;\n this.isStatic = false;\n this.isRootInsert = true;\n this.isComment = false;\n this.isCloned = false;\n this.isOnce = false;\n this.asyncFactory = asyncFactory;\n this.asyncMeta = undefined;\n this.isAsyncPlaceholder = false;\n};\n\nvar prototypeAccessors = { child: { configurable: true } };\n\n// DEPRECATED: alias for componentInstance for backwards compat.\n/* istanbul ignore next */\nprototypeAccessors.child.get = function () {\n return this.componentInstance\n};\n\nObject.defineProperties( VNode.prototype, prototypeAccessors );\n\nvar createEmptyVNode = function (text) {\n if ( text === void 0 ) text = '';\n\n var node = new VNode();\n node.text = text;\n node.isComment = true;\n return node\n};\n\nfunction createTextVNode (val) {\n return new VNode(undefined, undefined, undefined, String(val))\n}\n\n// optimized shallow clone\n// used for static nodes and slot nodes because they may be reused across\n// multiple renders, cloning them avoids errors when DOM manipulations rely\n// on their elm reference.\nfunction cloneVNode (vnode) {\n var cloned = new VNode(\n vnode.tag,\n vnode.data,\n vnode.children,\n vnode.text,\n vnode.elm,\n vnode.context,\n vnode.componentOptions,\n vnode.asyncFactory\n );\n cloned.ns = vnode.ns;\n cloned.isStatic = vnode.isStatic;\n cloned.key = vnode.key;\n cloned.isComment = vnode.isComment;\n cloned.fnContext = vnode.fnContext;\n cloned.fnOptions = vnode.fnOptions;\n cloned.fnScopeId = vnode.fnScopeId;\n cloned.isCloned = true;\n return cloned\n}\n\n/*\n * not type checking this file because flow doesn't play well with\n * dynamically accessing methods on Array prototype\n */\n\nvar arrayProto = Array.prototype;\nvar arrayMethods = Object.create(arrayProto);\n\nvar methodsToPatch = [\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse'\n];\n\n/**\n * Intercept mutating methods and emit events\n */\nmethodsToPatch.forEach(function (method) {\n // cache original method\n var original = arrayProto[method];\n def(arrayMethods, method, function mutator () {\n var args = [], len = arguments.length;\n while ( len-- ) args[ len ] = arguments[ len ];\n\n var result = original.apply(this, args);\n var ob = this.__ob__;\n var inserted;\n switch (method) {\n case 'push':\n case 'unshift':\n inserted = args;\n break\n case 'splice':\n inserted = args.slice(2);\n break\n }\n if (inserted) { ob.observeArray(inserted); }\n // notify change\n ob.dep.notify();\n return result\n });\n});\n\n/* */\n\nvar arrayKeys = Object.getOwnPropertyNames(arrayMethods);\n\n/**\n * In some cases we may want to disable observation inside a component's\n * update computation.\n */\nvar shouldObserve = true;\n\nfunction toggleObserving (value) {\n shouldObserve = value;\n}\n\n/**\n * Observer class that is attached to each observed\n * object. Once attached, the observer converts the target\n * object's property keys into getter/setters that\n * collect dependencies and dispatch updates.\n */\nvar Observer = function Observer (value) {\n this.value = value;\n this.dep = new Dep();\n this.vmCount = 0;\n def(value, '__ob__', this);\n if (Array.isArray(value)) {\n var augment = hasProto\n ? protoAugment\n : copyAugment;\n augment(value, arrayMethods, arrayKeys);\n this.observeArray(value);\n } else {\n this.walk(value);\n }\n};\n\n/**\n * Walk through each property and convert them into\n * getter/setters. This method should only be called when\n * value type is Object.\n */\nObserver.prototype.walk = function walk (obj) {\n var keys = Object.keys(obj);\n for (var i = 0; i < keys.length; i++) {\n defineReactive(obj, keys[i]);\n }\n};\n\n/**\n * Observe a list of Array items.\n */\nObserver.prototype.observeArray = function observeArray (items) {\n for (var i = 0, l = items.length; i < l; i++) {\n observe(items[i]);\n }\n};\n\n// helpers\n\n/**\n * Augment an target Object or Array by intercepting\n * the prototype chain using __proto__\n */\nfunction protoAugment (target, src, keys) {\n /* eslint-disable no-proto */\n target.__proto__ = src;\n /* eslint-enable no-proto */\n}\n\n/**\n * Augment an target Object or Array by defining\n * hidden properties.\n */\n/* istanbul ignore next */\nfunction copyAugment (target, src, keys) {\n for (var i = 0, l = keys.length; i < l; i++) {\n var key = keys[i];\n def(target, key, src[key]);\n }\n}\n\n/**\n * Attempt to create an observer instance for a value,\n * returns the new observer if successfully observed,\n * or the existing observer if the value already has one.\n */\nfunction observe (value, asRootData) {\n if (!isObject(value) || value instanceof VNode) {\n return\n }\n var ob;\n if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {\n ob = value.__ob__;\n } else if (\n shouldObserve &&\n !isServerRendering() &&\n (Array.isArray(value) || isPlainObject(value)) &&\n Object.isExtensible(value) &&\n !value._isVue\n ) {\n ob = new Observer(value);\n }\n if (asRootData && ob) {\n ob.vmCount++;\n }\n return ob\n}\n\n/**\n * Define a reactive property on an Object.\n */\nfunction defineReactive (\n obj,\n key,\n val,\n customSetter,\n shallow\n) {\n var dep = new Dep();\n\n var property = Object.getOwnPropertyDescriptor(obj, key);\n if (property && property.configurable === false) {\n return\n }\n\n // cater for pre-defined getter/setters\n var getter = property && property.get;\n if (!getter && arguments.length === 2) {\n val = obj[key];\n }\n var setter = property && property.set;\n\n var childOb = !shallow && observe(val);\n Object.defineProperty(obj, key, {\n enumerable: true,\n configurable: true,\n get: function reactiveGetter () {\n var value = getter ? getter.call(obj) : val;\n if (Dep.target) {\n dep.depend();\n if (childOb) {\n childOb.dep.depend();\n if (Array.isArray(value)) {\n dependArray(value);\n }\n }\n }\n return value\n },\n set: function reactiveSetter (newVal) {\n var value = getter ? getter.call(obj) : val;\n /* eslint-disable no-self-compare */\n if (newVal === value || (newVal !== newVal && value !== value)) {\n return\n }\n /* eslint-enable no-self-compare */\n if (\"development\" !== 'production' && customSetter) {\n customSetter();\n }\n if (setter) {\n setter.call(obj, newVal);\n } else {\n val = newVal;\n }\n childOb = !shallow && observe(newVal);\n dep.notify();\n }\n });\n}\n\n/**\n * Set a property on an object. Adds the new property and\n * triggers change notification if the property doesn't\n * already exist.\n */\nfunction set (target, key, val) {\n if (\"development\" !== 'production' &&\n (isUndef(target) || isPrimitive(target))\n ) {\n warn((\"Cannot set reactive property on undefined, null, or primitive value: \" + ((target))));\n }\n if (Array.isArray(target) && isValidArrayIndex(key)) {\n target.length = Math.max(target.length, key);\n target.splice(key, 1, val);\n return val\n }\n if (key in target && !(key in Object.prototype)) {\n target[key] = val;\n return val\n }\n var ob = (target).__ob__;\n if (target._isVue || (ob && ob.vmCount)) {\n \"development\" !== 'production' && warn(\n 'Avoid adding reactive properties to a Vue instance or its root $data ' +\n 'at runtime - declare it upfront in the data option.'\n );\n return val\n }\n if (!ob) {\n target[key] = val;\n return val\n }\n defineReactive(ob.value, key, val);\n ob.dep.notify();\n return val\n}\n\n/**\n * Delete a property and trigger change if necessary.\n */\nfunction del (target, key) {\n if (\"development\" !== 'production' &&\n (isUndef(target) || isPrimitive(target))\n ) {\n warn((\"Cannot delete reactive property on undefined, null, or primitive value: \" + ((target))));\n }\n if (Array.isArray(target) && isValidArrayIndex(key)) {\n target.splice(key, 1);\n return\n }\n var ob = (target).__ob__;\n if (target._isVue || (ob && ob.vmCount)) {\n \"development\" !== 'production' && warn(\n 'Avoid deleting properties on a Vue instance or its root $data ' +\n '- just set it to null.'\n );\n return\n }\n if (!hasOwn(target, key)) {\n return\n }\n delete target[key];\n if (!ob) {\n return\n }\n ob.dep.notify();\n}\n\n/**\n * Collect dependencies on array elements when the array is touched, since\n * we cannot intercept array element access like property getters.\n */\nfunction dependArray (value) {\n for (var e = (void 0), i = 0, l = value.length; i < l; i++) {\n e = value[i];\n e && e.__ob__ && e.__ob__.dep.depend();\n if (Array.isArray(e)) {\n dependArray(e);\n }\n }\n}\n\n/* */\n\n/**\n * Option overwriting strategies are functions that handle\n * how to merge a parent option value and a child option\n * value into the final value.\n */\nvar strats = config.optionMergeStrategies;\n\n/**\n * Options with restrictions\n */\n{\n strats.el = strats.propsData = function (parent, child, vm, key) {\n if (!vm) {\n warn(\n \"option \\\"\" + key + \"\\\" can only be used during instance \" +\n 'creation with the `new` keyword.'\n );\n }\n return defaultStrat(parent, child)\n };\n}\n\n/**\n * Helper that recursively merges two data objects together.\n */\nfunction mergeData (to, from) {\n if (!from) { return to }\n var key, toVal, fromVal;\n var keys = Object.keys(from);\n for (var i = 0; i < keys.length; i++) {\n key = keys[i];\n toVal = to[key];\n fromVal = from[key];\n if (!hasOwn(to, key)) {\n set(to, key, fromVal);\n } else if (isPlainObject(toVal) && isPlainObject(fromVal)) {\n mergeData(toVal, fromVal);\n }\n }\n return to\n}\n\n/**\n * Data\n */\nfunction mergeDataOrFn (\n parentVal,\n childVal,\n vm\n) {\n if (!vm) {\n // in a Vue.extend merge, both should be functions\n if (!childVal) {\n return parentVal\n }\n if (!parentVal) {\n return childVal\n }\n // when parentVal & childVal are both present,\n // we need to return a function that returns the\n // merged result of both functions... no need to\n // check if parentVal is a function here because\n // it has to be a function to pass previous merges.\n return function mergedDataFn () {\n return mergeData(\n typeof childVal === 'function' ? childVal.call(this, this) : childVal,\n typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal\n )\n }\n } else {\n return function mergedInstanceDataFn () {\n // instance merge\n var instanceData = typeof childVal === 'function'\n ? childVal.call(vm, vm)\n : childVal;\n var defaultData = typeof parentVal === 'function'\n ? parentVal.call(vm, vm)\n : parentVal;\n if (instanceData) {\n return mergeData(instanceData, defaultData)\n } else {\n return defaultData\n }\n }\n }\n}\n\nstrats.data = function (\n parentVal,\n childVal,\n vm\n) {\n if (!vm) {\n if (childVal && typeof childVal !== 'function') {\n \"development\" !== 'production' && warn(\n 'The \"data\" option should be a function ' +\n 'that returns a per-instance value in component ' +\n 'definitions.',\n vm\n );\n\n return parentVal\n }\n return mergeDataOrFn(parentVal, childVal)\n }\n\n return mergeDataOrFn(parentVal, childVal, vm)\n};\n\n/**\n * Hooks and props are merged as arrays.\n */\nfunction mergeHook (\n parentVal,\n childVal\n) {\n return childVal\n ? parentVal\n ? parentVal.concat(childVal)\n : Array.isArray(childVal)\n ? childVal\n : [childVal]\n : parentVal\n}\n\nLIFECYCLE_HOOKS.forEach(function (hook) {\n strats[hook] = mergeHook;\n});\n\n/**\n * Assets\n *\n * When a vm is present (instance creation), we need to do\n * a three-way merge between constructor options, instance\n * options and parent options.\n */\nfunction mergeAssets (\n parentVal,\n childVal,\n vm,\n key\n) {\n var res = Object.create(parentVal || null);\n if (childVal) {\n \"development\" !== 'production' && assertObjectType(key, childVal, vm);\n return extend(res, childVal)\n } else {\n return res\n }\n}\n\nASSET_TYPES.forEach(function (type) {\n strats[type + 's'] = mergeAssets;\n});\n\n/**\n * Watchers.\n *\n * Watchers hashes should not overwrite one\n * another, so we merge them as arrays.\n */\nstrats.watch = function (\n parentVal,\n childVal,\n vm,\n key\n) {\n // work around Firefox's Object.prototype.watch...\n if (parentVal === nativeWatch) { parentVal = undefined; }\n if (childVal === nativeWatch) { childVal = undefined; }\n /* istanbul ignore if */\n if (!childVal) { return Object.create(parentVal || null) }\n {\n assertObjectType(key, childVal, vm);\n }\n if (!parentVal) { return childVal }\n var ret = {};\n extend(ret, parentVal);\n for (var key$1 in childVal) {\n var parent = ret[key$1];\n var child = childVal[key$1];\n if (parent && !Array.isArray(parent)) {\n parent = [parent];\n }\n ret[key$1] = parent\n ? parent.concat(child)\n : Array.isArray(child) ? child : [child];\n }\n return ret\n};\n\n/**\n * Other object hashes.\n */\nstrats.props =\nstrats.methods =\nstrats.inject =\nstrats.computed = function (\n parentVal,\n childVal,\n vm,\n key\n) {\n if (childVal && \"development\" !== 'production') {\n assertObjectType(key, childVal, vm);\n }\n if (!parentVal) { return childVal }\n var ret = Object.create(null);\n extend(ret, parentVal);\n if (childVal) { extend(ret, childVal); }\n return ret\n};\nstrats.provide = mergeDataOrFn;\n\n/**\n * Default strategy.\n */\nvar defaultStrat = function (parentVal, childVal) {\n return childVal === undefined\n ? parentVal\n : childVal\n};\n\n/**\n * Validate component names\n */\nfunction checkComponents (options) {\n for (var key in options.components) {\n validateComponentName(key);\n }\n}\n\nfunction validateComponentName (name) {\n if (!/^[a-zA-Z][\\w-]*$/.test(name)) {\n warn(\n 'Invalid component name: \"' + name + '\". Component names ' +\n 'can only contain alphanumeric characters and the hyphen, ' +\n 'and must start with a letter.'\n );\n }\n if (isBuiltInTag(name) || config.isReservedTag(name)) {\n warn(\n 'Do not use built-in or reserved HTML elements as component ' +\n 'id: ' + name\n );\n }\n}\n\n/**\n * Ensure all props option syntax are normalized into the\n * Object-based format.\n */\nfunction normalizeProps (options, vm) {\n var props = options.props;\n if (!props) { return }\n var res = {};\n var i, val, name;\n if (Array.isArray(props)) {\n i = props.length;\n while (i--) {\n val = props[i];\n if (typeof val === 'string') {\n name = camelize(val);\n res[name] = { type: null };\n } else {\n warn('props must be strings when using array syntax.');\n }\n }\n } else if (isPlainObject(props)) {\n for (var key in props) {\n val = props[key];\n name = camelize(key);\n res[name] = isPlainObject(val)\n ? val\n : { type: val };\n }\n } else {\n warn(\n \"Invalid value for option \\\"props\\\": expected an Array or an Object, \" +\n \"but got \" + (toRawType(props)) + \".\",\n vm\n );\n }\n options.props = res;\n}\n\n/**\n * Normalize all injections into Object-based format\n */\nfunction normalizeInject (options, vm) {\n var inject = options.inject;\n if (!inject) { return }\n var normalized = options.inject = {};\n if (Array.isArray(inject)) {\n for (var i = 0; i < inject.length; i++) {\n normalized[inject[i]] = { from: inject[i] };\n }\n } else if (isPlainObject(inject)) {\n for (var key in inject) {\n var val = inject[key];\n normalized[key] = isPlainObject(val)\n ? extend({ from: key }, val)\n : { from: val };\n }\n } else {\n warn(\n \"Invalid value for option \\\"inject\\\": expected an Array or an Object, \" +\n \"but got \" + (toRawType(inject)) + \".\",\n vm\n );\n }\n}\n\n/**\n * Normalize raw function directives into object format.\n */\nfunction normalizeDirectives (options) {\n var dirs = options.directives;\n if (dirs) {\n for (var key in dirs) {\n var def = dirs[key];\n if (typeof def === 'function') {\n dirs[key] = { bind: def, update: def };\n }\n }\n }\n}\n\nfunction assertObjectType (name, value, vm) {\n if (!isPlainObject(value)) {\n warn(\n \"Invalid value for option \\\"\" + name + \"\\\": expected an Object, \" +\n \"but got \" + (toRawType(value)) + \".\",\n vm\n );\n }\n}\n\n/**\n * Merge two option objects into a new one.\n * Core utility used in both instantiation and inheritance.\n */\nfunction mergeOptions (\n parent,\n child,\n vm\n) {\n {\n checkComponents(child);\n }\n\n if (typeof child === 'function') {\n child = child.options;\n }\n\n normalizeProps(child, vm);\n normalizeInject(child, vm);\n normalizeDirectives(child);\n var extendsFrom = child.extends;\n if (extendsFrom) {\n parent = mergeOptions(parent, extendsFrom, vm);\n }\n if (child.mixins) {\n for (var i = 0, l = child.mixins.length; i < l; i++) {\n parent = mergeOptions(parent, child.mixins[i], vm);\n }\n }\n var options = {};\n var key;\n for (key in parent) {\n mergeField(key);\n }\n for (key in child) {\n if (!hasOwn(parent, key)) {\n mergeField(key);\n }\n }\n function mergeField (key) {\n var strat = strats[key] || defaultStrat;\n options[key] = strat(parent[key], child[key], vm, key);\n }\n return options\n}\n\n/**\n * Resolve an asset.\n * This function is used because child instances need access\n * to assets defined in its ancestor chain.\n */\nfunction resolveAsset (\n options,\n type,\n id,\n warnMissing\n) {\n /* istanbul ignore if */\n if (typeof id !== 'string') {\n return\n }\n var assets = options[type];\n // check local registration variations first\n if (hasOwn(assets, id)) { return assets[id] }\n var camelizedId = camelize(id);\n if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }\n var PascalCaseId = capitalize(camelizedId);\n if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }\n // fallback to prototype chain\n var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];\n if (\"development\" !== 'production' && warnMissing && !res) {\n warn(\n 'Failed to resolve ' + type.slice(0, -1) + ': ' + id,\n options\n );\n }\n return res\n}\n\n/* */\n\nfunction validateProp (\n key,\n propOptions,\n propsData,\n vm\n) {\n var prop = propOptions[key];\n var absent = !hasOwn(propsData, key);\n var value = propsData[key];\n // boolean casting\n var booleanIndex = getTypeIndex(Boolean, prop.type);\n if (booleanIndex > -1) {\n if (absent && !hasOwn(prop, 'default')) {\n value = false;\n } else if (value === '' || value === hyphenate(key)) {\n // only cast empty string / same name to boolean if\n // boolean has higher priority\n var stringIndex = getTypeIndex(String, prop.type);\n if (stringIndex < 0 || booleanIndex < stringIndex) {\n value = true;\n }\n }\n }\n // check default value\n if (value === undefined) {\n value = getPropDefaultValue(vm, prop, key);\n // since the default value is a fresh copy,\n // make sure to observe it.\n var prevShouldObserve = shouldObserve;\n toggleObserving(true);\n observe(value);\n toggleObserving(prevShouldObserve);\n }\n {\n assertProp(prop, key, value, vm, absent);\n }\n return value\n}\n\n/**\n * Get the default value of a prop.\n */\nfunction getPropDefaultValue (vm, prop, key) {\n // no default, return undefined\n if (!hasOwn(prop, 'default')) {\n return undefined\n }\n var def = prop.default;\n // warn against non-factory defaults for Object & Array\n if (\"development\" !== 'production' && isObject(def)) {\n warn(\n 'Invalid default value for prop \"' + key + '\": ' +\n 'Props with type Object/Array must use a factory function ' +\n 'to return the default value.',\n vm\n );\n }\n // the raw prop value was also undefined from previous render,\n // return previous default value to avoid unnecessary watcher trigger\n if (vm && vm.$options.propsData &&\n vm.$options.propsData[key] === undefined &&\n vm._props[key] !== undefined\n ) {\n return vm._props[key]\n }\n // call factory function for non-Function types\n // a value is Function if its prototype is function even across different execution context\n return typeof def === 'function' && getType(prop.type) !== 'Function'\n ? def.call(vm)\n : def\n}\n\n/**\n * Assert whether a prop is valid.\n */\nfunction assertProp (\n prop,\n name,\n value,\n vm,\n absent\n) {\n if (prop.required && absent) {\n warn(\n 'Missing required prop: \"' + name + '\"',\n vm\n );\n return\n }\n if (value == null && !prop.required) {\n return\n }\n var type = prop.type;\n var valid = !type || type === true;\n var expectedTypes = [];\n if (type) {\n if (!Array.isArray(type)) {\n type = [type];\n }\n for (var i = 0; i < type.length && !valid; i++) {\n var assertedType = assertType(value, type[i]);\n expectedTypes.push(assertedType.expectedType || '');\n valid = assertedType.valid;\n }\n }\n if (!valid) {\n warn(\n \"Invalid prop: type check failed for prop \\\"\" + name + \"\\\".\" +\n \" Expected \" + (expectedTypes.map(capitalize).join(', ')) +\n \", got \" + (toRawType(value)) + \".\",\n vm\n );\n return\n }\n var validator = prop.validator;\n if (validator) {\n if (!validator(value)) {\n warn(\n 'Invalid prop: custom validator check failed for prop \"' + name + '\".',\n vm\n );\n }\n }\n}\n\nvar simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/;\n\nfunction assertType (value, type) {\n var valid;\n var expectedType = getType(type);\n if (simpleCheckRE.test(expectedType)) {\n var t = typeof value;\n valid = t === expectedType.toLowerCase();\n // for primitive wrapper objects\n if (!valid && t === 'object') {\n valid = value instanceof type;\n }\n } else if (expectedType === 'Object') {\n valid = isPlainObject(value);\n } else if (expectedType === 'Array') {\n valid = Array.isArray(value);\n } else {\n valid = value instanceof type;\n }\n return {\n valid: valid,\n expectedType: expectedType\n }\n}\n\n/**\n * Use function string name to check built-in types,\n * because a simple equality check will fail when running\n * across different vms / iframes.\n */\nfunction getType (fn) {\n var match = fn && fn.toString().match(/^\\s*function (\\w+)/);\n return match ? match[1] : ''\n}\n\nfunction isSameType (a, b) {\n return getType(a) === getType(b)\n}\n\nfunction getTypeIndex (type, expectedTypes) {\n if (!Array.isArray(expectedTypes)) {\n return isSameType(expectedTypes, type) ? 0 : -1\n }\n for (var i = 0, len = expectedTypes.length; i < len; i++) {\n if (isSameType(expectedTypes[i], type)) {\n return i\n }\n }\n return -1\n}\n\n/* */\n\nfunction handleError (err, vm, info) {\n if (vm) {\n var cur = vm;\n while ((cur = cur.$parent)) {\n var hooks = cur.$options.errorCaptured;\n if (hooks) {\n for (var i = 0; i < hooks.length; i++) {\n try {\n var capture = hooks[i].call(cur, err, vm, info) === false;\n if (capture) { return }\n } catch (e) {\n globalHandleError(e, cur, 'errorCaptured hook');\n }\n }\n }\n }\n }\n globalHandleError(err, vm, info);\n}\n\nfunction globalHandleError (err, vm, info) {\n if (config.errorHandler) {\n try {\n return config.errorHandler.call(null, err, vm, info)\n } catch (e) {\n logError(e, null, 'config.errorHandler');\n }\n }\n logError(err, vm, info);\n}\n\nfunction logError (err, vm, info) {\n {\n warn((\"Error in \" + info + \": \\\"\" + (err.toString()) + \"\\\"\"), vm);\n }\n /* istanbul ignore else */\n if ((inBrowser || inWeex) && typeof console !== 'undefined') {\n console.error(err);\n } else {\n throw err\n }\n}\n\n/* */\n/* globals MessageChannel */\n\nvar callbacks = [];\nvar pending = false;\n\nfunction flushCallbacks () {\n pending = false;\n var copies = callbacks.slice(0);\n callbacks.length = 0;\n for (var i = 0; i < copies.length; i++) {\n copies[i]();\n }\n}\n\n// Here we have async deferring wrappers using both microtasks and (macro) tasks.\n// In < 2.4 we used microtasks everywhere, but there are some scenarios where\n// microtasks have too high a priority and fire in between supposedly\n// sequential events (e.g. #4521, #6690) or even between bubbling of the same\n// event (#6566). However, using (macro) tasks everywhere also has subtle problems\n// when state is changed right before repaint (e.g. #6813, out-in transitions).\n// Here we use microtask by default, but expose a way to force (macro) task when\n// needed (e.g. in event handlers attached by v-on).\nvar microTimerFunc;\nvar macroTimerFunc;\nvar useMacroTask = false;\n\n// Determine (macro) task defer implementation.\n// Technically setImmediate should be the ideal choice, but it's only available\n// in IE. The only polyfill that consistently queues the callback after all DOM\n// events triggered in the same loop is by using MessageChannel.\n/* istanbul ignore if */\nif (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {\n macroTimerFunc = function () {\n setImmediate(flushCallbacks);\n };\n} else if (typeof MessageChannel !== 'undefined' && (\n isNative(MessageChannel) ||\n // PhantomJS\n MessageChannel.toString() === '[object MessageChannelConstructor]'\n)) {\n var channel = new MessageChannel();\n var port = channel.port2;\n channel.port1.onmessage = flushCallbacks;\n macroTimerFunc = function () {\n port.postMessage(1);\n };\n} else {\n /* istanbul ignore next */\n macroTimerFunc = function () {\n setTimeout(flushCallbacks, 0);\n };\n}\n\n// Determine microtask defer implementation.\n/* istanbul ignore next, $flow-disable-line */\nif (typeof Promise !== 'undefined' && isNative(Promise)) {\n var p = Promise.resolve();\n microTimerFunc = function () {\n p.then(flushCallbacks);\n // in problematic UIWebViews, Promise.then doesn't completely break, but\n // it can get stuck in a weird state where callbacks are pushed into the\n // microtask queue but the queue isn't being flushed, until the browser\n // needs to do some other work, e.g. handle a timer. Therefore we can\n // \"force\" the microtask queue to be flushed by adding an empty timer.\n if (isIOS) { setTimeout(noop); }\n };\n} else {\n // fallback to macro\n microTimerFunc = macroTimerFunc;\n}\n\n/**\n * Wrap a function so that if any code inside triggers state change,\n * the changes are queued using a (macro) task instead of a microtask.\n */\nfunction withMacroTask (fn) {\n return fn._withTask || (fn._withTask = function () {\n useMacroTask = true;\n var res = fn.apply(null, arguments);\n useMacroTask = false;\n return res\n })\n}\n\nfunction nextTick (cb, ctx) {\n var _resolve;\n callbacks.push(function () {\n if (cb) {\n try {\n cb.call(ctx);\n } catch (e) {\n handleError(e, ctx, 'nextTick');\n }\n } else if (_resolve) {\n _resolve(ctx);\n }\n });\n if (!pending) {\n pending = true;\n if (useMacroTask) {\n macroTimerFunc();\n } else {\n microTimerFunc();\n }\n }\n // $flow-disable-line\n if (!cb && typeof Promise !== 'undefined') {\n return new Promise(function (resolve) {\n _resolve = resolve;\n })\n }\n}\n\n/* */\n\n/* not type checking this file because flow doesn't play well with Proxy */\n\nvar initProxy;\n\n{\n var allowedGlobals = makeMap(\n 'Infinity,undefined,NaN,isFinite,isNaN,' +\n 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +\n 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +\n 'require' // for Webpack/Browserify\n );\n\n var warnNonPresent = function (target, key) {\n warn(\n \"Property or method \\\"\" + key + \"\\\" is not defined on the instance but \" +\n 'referenced during render. Make sure that this property is reactive, ' +\n 'either in the data option, or for class-based components, by ' +\n 'initializing the property. ' +\n 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',\n target\n );\n };\n\n var hasProxy =\n typeof Proxy !== 'undefined' && isNative(Proxy);\n\n if (hasProxy) {\n var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact');\n config.keyCodes = new Proxy(config.keyCodes, {\n set: function set (target, key, value) {\n if (isBuiltInModifier(key)) {\n warn((\"Avoid overwriting built-in modifier in config.keyCodes: .\" + key));\n return false\n } else {\n target[key] = value;\n return true\n }\n }\n });\n }\n\n var hasHandler = {\n has: function has (target, key) {\n var has = key in target;\n var isAllowed = allowedGlobals(key) || key.charAt(0) === '_';\n if (!has && !isAllowed) {\n warnNonPresent(target, key);\n }\n return has || !isAllowed\n }\n };\n\n var getHandler = {\n get: function get (target, key) {\n if (typeof key === 'string' && !(key in target)) {\n warnNonPresent(target, key);\n }\n return target[key]\n }\n };\n\n initProxy = function initProxy (vm) {\n if (hasProxy) {\n // determine which proxy handler to use\n var options = vm.$options;\n var handlers = options.render && options.render._withStripped\n ? getHandler\n : hasHandler;\n vm._renderProxy = new Proxy(vm, handlers);\n } else {\n vm._renderProxy = vm;\n }\n };\n}\n\n/* */\n\nvar seenObjects = new _Set();\n\n/**\n * Recursively traverse an object to evoke all converted\n * getters, so that every nested property inside the object\n * is collected as a \"deep\" dependency.\n */\nfunction traverse (val) {\n _traverse(val, seenObjects);\n seenObjects.clear();\n}\n\nfunction _traverse (val, seen) {\n var i, keys;\n var isA = Array.isArray(val);\n if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {\n return\n }\n if (val.__ob__) {\n var depId = val.__ob__.dep.id;\n if (seen.has(depId)) {\n return\n }\n seen.add(depId);\n }\n if (isA) {\n i = val.length;\n while (i--) { _traverse(val[i], seen); }\n } else {\n keys = Object.keys(val);\n i = keys.length;\n while (i--) { _traverse(val[keys[i]], seen); }\n }\n}\n\nvar mark;\nvar measure;\n\n{\n var perf = inBrowser && window.performance;\n /* istanbul ignore if */\n if (\n perf &&\n perf.mark &&\n perf.measure &&\n perf.clearMarks &&\n perf.clearMeasures\n ) {\n mark = function (tag) { return perf.mark(tag); };\n measure = function (name, startTag, endTag) {\n perf.measure(name, startTag, endTag);\n perf.clearMarks(startTag);\n perf.clearMarks(endTag);\n perf.clearMeasures(name);\n };\n }\n}\n\n/* */\n\nvar normalizeEvent = cached(function (name) {\n var passive = name.charAt(0) === '&';\n name = passive ? name.slice(1) : name;\n var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first\n name = once$$1 ? name.slice(1) : name;\n var capture = name.charAt(0) === '!';\n name = capture ? name.slice(1) : name;\n return {\n name: name,\n once: once$$1,\n capture: capture,\n passive: passive\n }\n});\n\nfunction createFnInvoker (fns) {\n function invoker () {\n var arguments$1 = arguments;\n\n var fns = invoker.fns;\n if (Array.isArray(fns)) {\n var cloned = fns.slice();\n for (var i = 0; i < cloned.length; i++) {\n cloned[i].apply(null, arguments$1);\n }\n } else {\n // return handler return value for single handlers\n return fns.apply(null, arguments)\n }\n }\n invoker.fns = fns;\n return invoker\n}\n\nfunction updateListeners (\n on,\n oldOn,\n add,\n remove$$1,\n vm\n) {\n var name, def, cur, old, event;\n for (name in on) {\n def = cur = on[name];\n old = oldOn[name];\n event = normalizeEvent(name);\n /* istanbul ignore if */\n if (isUndef(cur)) {\n \"development\" !== 'production' && warn(\n \"Invalid handler for event \\\"\" + (event.name) + \"\\\": got \" + String(cur),\n vm\n );\n } else if (isUndef(old)) {\n if (isUndef(cur.fns)) {\n cur = on[name] = createFnInvoker(cur);\n }\n add(event.name, cur, event.once, event.capture, event.passive, event.params);\n } else if (cur !== old) {\n old.fns = cur;\n on[name] = old;\n }\n }\n for (name in oldOn) {\n if (isUndef(on[name])) {\n event = normalizeEvent(name);\n remove$$1(event.name, oldOn[name], event.capture);\n }\n }\n}\n\n/* */\n\nfunction mergeVNodeHook (def, hookKey, hook) {\n if (def instanceof VNode) {\n def = def.data.hook || (def.data.hook = {});\n }\n var invoker;\n var oldHook = def[hookKey];\n\n function wrappedHook () {\n hook.apply(this, arguments);\n // important: remove merged hook to ensure it's called only once\n // and prevent memory leak\n remove(invoker.fns, wrappedHook);\n }\n\n if (isUndef(oldHook)) {\n // no existing hook\n invoker = createFnInvoker([wrappedHook]);\n } else {\n /* istanbul ignore if */\n if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {\n // already a merged invoker\n invoker = oldHook;\n invoker.fns.push(wrappedHook);\n } else {\n // existing plain hook\n invoker = createFnInvoker([oldHook, wrappedHook]);\n }\n }\n\n invoker.merged = true;\n def[hookKey] = invoker;\n}\n\n/* */\n\nfunction extractPropsFromVNodeData (\n data,\n Ctor,\n tag\n) {\n // we are only extracting raw values here.\n // validation and default values are handled in the child\n // component itself.\n var propOptions = Ctor.options.props;\n if (isUndef(propOptions)) {\n return\n }\n var res = {};\n var attrs = data.attrs;\n var props = data.props;\n if (isDef(attrs) || isDef(props)) {\n for (var key in propOptions) {\n var altKey = hyphenate(key);\n {\n var keyInLowerCase = key.toLowerCase();\n if (\n key !== keyInLowerCase &&\n attrs && hasOwn(attrs, keyInLowerCase)\n ) {\n tip(\n \"Prop \\\"\" + keyInLowerCase + \"\\\" is passed to component \" +\n (formatComponentName(tag || Ctor)) + \", but the declared prop name is\" +\n \" \\\"\" + key + \"\\\". \" +\n \"Note that HTML attributes are case-insensitive and camelCased \" +\n \"props need to use their kebab-case equivalents when using in-DOM \" +\n \"templates. You should probably use \\\"\" + altKey + \"\\\" instead of \\\"\" + key + \"\\\".\"\n );\n }\n }\n checkProp(res, props, key, altKey, true) ||\n checkProp(res, attrs, key, altKey, false);\n }\n }\n return res\n}\n\nfunction checkProp (\n res,\n hash,\n key,\n altKey,\n preserve\n) {\n if (isDef(hash)) {\n if (hasOwn(hash, key)) {\n res[key] = hash[key];\n if (!preserve) {\n delete hash[key];\n }\n return true\n } else if (hasOwn(hash, altKey)) {\n res[key] = hash[altKey];\n if (!preserve) {\n delete hash[altKey];\n }\n return true\n }\n }\n return false\n}\n\n/* */\n\n// The template compiler attempts to minimize the need for normalization by\n// statically analyzing the template at compile time.\n//\n// For plain HTML markup, normalization can be completely skipped because the\n// generated render function is guaranteed to return Array. There are\n// two cases where extra normalization is needed:\n\n// 1. When the children contains components - because a functional component\n// may return an Array instead of a single root. In this case, just a simple\n// normalization is needed - if any child is an Array, we flatten the whole\n// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep\n// because functional components already normalize their own children.\nfunction simpleNormalizeChildren (children) {\n for (var i = 0; i < children.length; i++) {\n if (Array.isArray(children[i])) {\n return Array.prototype.concat.apply([], children)\n }\n }\n return children\n}\n\n// 2. When the children contains constructs that always generated nested Arrays,\n// e.g.