Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

26 conflict name #40

Merged
merged 3 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ ij_java_imports_layout = *,|,javax.**,java.**,|,$*

[*.yaml]
indent_size = 2

[*.ts]
ij_javascript_enforce_trailing_comma = whenmultiline
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* [vojtechhabarta/typescript-generator](https://github.com/vojtechhabarta/typescript-generator)

## Documentation
[User Guide](doc/Usage.md)
[Development Guide](doc/Development.md)
* [User Guide](doc/Usage.md)
* [Development Guide](doc/Development.md)

## Authors
Cause Chung (cuzfrog@gmail.com)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
import java.lang.annotation.Target;

/**
* <p>Share a type. <a href="https://github.com/cuzfrog/SharedType">Website</a></p>
* <br>
* <b>Inner class:</b>
* <p>
* Declared inner and nested types will not be included by default, unless they are referenced by other types.
* Non-static inner classes are not supported, see documentation for details.
* TODO: doc for nested types
* </p>
*
Expand All @@ -20,7 +23,17 @@
@Documented
public @interface SharedType {
/**
* The name of the emitted type. If not specified, the simple name of the annotated type will be used.
* <p>
* The name of the emitted type. If not specified, the simple name of the annotated type will be used.
* This may be used to help avoid conflicting names in target output.
* </p>
* <br>
* <p>
* How possibly conflicting names are resolved:
* <ul>
* <li>Typescript: simple name of a class is used as type name. Duplicate names are not allowed.</li>
* </ul>
* </p>
*/
String name() default "";

Expand Down
6 changes: 5 additions & 1 deletion client-test/typescript/tests/enum-union.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {DependencyClassA, DependencyClassB, DependencyClassC, EnumGalaxy, EnumSize, EnumTShirt, JavaRecord} from "../src/index.js";
import type {DependencyClassA, DependencyClassB, DependencyClassC, EnumGalaxy, EnumSize, EnumTShirt, JavaRecord, AnotherJavaClass} from "../src/index.js";

export const list1: EnumGalaxy[] = ["Andromeda", "MilkyWay", "Triangulum"];
export const record1: Record<EnumTShirt, number> = {
Expand Down Expand Up @@ -51,3 +51,7 @@ export const obj: Omit<JavaRecord<string, number>, "aVoid" | "genericMap"> = {
primitiveShort: 0,
string: "",
};

export const anotherJavaClass: AnotherJavaClass = {
value: 333,
}
47 changes: 28 additions & 19 deletions doc/Development.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Development Guide

## Architecture

`Source code` ==Parser=> `Type definition` + `unresolved types` ==Resolver=> `Type definition` + `resolved types` ==Writer=> `target schema/language`

Internal types also have javadoc for more information.
#### Project structure
* `annotation` contains the annotation type `@SharedType` as client code compile-time dependency.
* `processor` contains annotation processor logic, put on client's annotation processing path.
* `internal` contains domain types used in `processor` and integration test.
* `it` contains integration tests, which do metadata verification by deserializing metadata objects.
* `java8` contains major types for tests.
* `java17` uses symlink to reuse types in `java8` then does more type checks, e.g. for Java `record`.
* `client-test` contains target languages' tests respectively against generated code.

## Setup
**Linux is assumed**. If you use Windows, you can use WSL with a remotely connected IDE. Windows 11 supports GUI app inside WSL.

Expand All @@ -11,45 +25,40 @@ Optionally mount tmpfs to save your disk by:
```bash
./mount-tmpfs.sh
```

## Style check
```bash
./mvnw editorconfig:check
```

## Debug
Debug annotation processor by run maven build:
```bash
./mvnd <your args goes here>
```
Then attach your debugger on it.

## Run test
## Development
### Run test
If you encounter compilation problems with your IDE, delegate compilation to maven.
Before run test in IDE/individual module, run `./mvnw clean install -DskipTests` to build dependency classes.

#### E.g. run integration test locally:
```bash
./mvnw clean install -DskipTests -q && ./mvnw test -pl it/java17 -pl it/java8
```

#### Run local verification with all java tests
```bash
./mvnw verify
```

#### Verify JDK8 compatibility locally
Setup `JAVA8_HOME` to point to your Java8 installation.
Setup `JAVA8_HOME` to point to your Java8 installation. Open a new terminal and run:
```bash
. setenv 8
./mvnw verify -pl it/java8
```

#### Run client tests locally
Client tests are run in target languages in respective dir inside `./client-test`. They do basic type checking.
* Typescript. `. setenv && npm i && npm run test`
#### Misc
Style check:
```bash
./mvnw editorconfig:check
```
Debug annotation processor by run maven build:
```bash
./mvnd <your args goes here>
```
Then attach your debugger on it.


## Coding Style Guide
1. since annotation processing is one shot execution, JIT is not likely to optimize the code. So prefer plain loop than long calling stacks like Stream chains.
2. no adding dependencies without strong justification.
3. Lombok is used in this project, but do not abuse. Only use it to replace unavoidable boilerplate code, and not to increase the bytecode size.
10 changes: 10 additions & 0 deletions internal/src/main/java/org/sharedtype/domain/ArrayTypeInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

/**
* Represents an array-like type.
* During parsing, a predefined array-like type and its subtypes is captured as this class.
* A type will be recognized as this type with higher priority than {@link ConcreteTypeInfo}.
* <br>
* Predefined array-like types can be configured in global properties. Default is {@link java.lang.Iterable}.
*
* @see ConcreteTypeInfo
* @author Cause Chung
*/
@RequiredArgsConstructor
@EqualsAndHashCode
public final class ArrayTypeInfo implements TypeInfo {
Expand Down
8 changes: 5 additions & 3 deletions internal/src/main/java/org/sharedtype/domain/ClassDef.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import java.util.stream.Collectors;

/**
* Represents info captured from an interface, class, or record.
* Represents structural info captured from an interface, class, or record.
*
* @author Cause Chung
*/
@Builder
@EqualsAndHashCode(of = "qualifiedName")
Expand Down Expand Up @@ -77,13 +79,13 @@ public String toString() {
}

private String typeVariablesToString() {
return typeVariables.isEmpty() ? "" : "<" + String.join(",", typeVariables.stream().map(TypeVariableInfo::toString).collect(Collectors.toList())) + ">";
return typeVariables.isEmpty() ? "" : "<" + typeVariables.stream().map(TypeVariableInfo::toString).collect(Collectors.joining(",")) + ">";
}

private String supertypesToString() {
if (supertypes.isEmpty()) {
return "";
}
return " extends " + String.join(" & ", supertypes.stream().map(t -> t + (t.resolved() ? "" : "?")).collect(Collectors.toList()));
return " extends " + supertypes.stream().map(t -> t + (t.resolved() ? "" : "?")).collect(Collectors.joining(" & "));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

import java.io.Serializable;

/**
* Represents internal components in a {@link TypeDef}.
*
* @author Cause Chung
*/
public interface ComponentInfo extends Serializable {
boolean resolved();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
import java.util.List;
import java.util.stream.Collectors;

/**
* Represents a primitive type or object type that requires its target representation,
* and is not recognized as an array-like type.
* Like {@link java.lang.String} in typescript as "string", int in typescript as "number".
*
* @see ArrayTypeInfo
* @author Cause Chung
*/
@EqualsAndHashCode(of = "qualifiedName")
@Builder
public final class ConcreteTypeInfo implements TypeInfo {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package org.sharedtype.domain;

/**
* Represents a constant literal.
* Only literals with values resolvable at compile time are supported.
*
* @author Cause Chung
*/
public final class ConstantInfo {

}
3 changes: 3 additions & 0 deletions internal/src/main/java/org/sharedtype/domain/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import java.util.HashMap;
import java.util.Map;

/**
* @author Cause Chung
*/
public final class Constants {
public static final String ANNOTATION_QUALIFIED_NAME = SharedType.class.getName();

Expand Down
5 changes: 5 additions & 0 deletions internal/src/main/java/org/sharedtype/domain/EnumDef.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import java.util.List;
import java.util.stream.Collectors;

/**
* Represents an enum.
*
* @author Cause Chung
*/
@EqualsAndHashCode(of = "qualifiedName")
@Builder
public final class EnumDef implements TypeDef {
Expand Down
10 changes: 10 additions & 0 deletions internal/src/main/java/org/sharedtype/domain/EnumValueInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@

import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import org.sharedtype.annotation.SharedType;

/**
* Represents an enum value, which is the value in the target code that corresponds to an enum constant.
* <br>
* By default, enum value is String value of the enum constant. It can be configured with {@link SharedType.EnumValue}.
*
* @see EnumDef
* @see SharedType.EnumValue
* @author Cause Chung
*/
@EqualsAndHashCode
@RequiredArgsConstructor
public final class EnumValueInfo implements ComponentInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import javax.lang.model.element.Modifier;
import java.util.Set;

/**
* Represents a field or accessor.
*
* @author Cause Chung
*/
@Builder
public final class FieldComponentInfo implements ComponentInfo {
private final String name;
Expand Down
8 changes: 8 additions & 0 deletions internal/src/main/java/org/sharedtype/domain/TypeDef.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
import java.io.Serializable;
import java.util.List;

/**
* Type definition. Represents type structure used for target output.
* This is the unit for target code generation.
* On the other hand, {@link TypeInfo} represents a type without structural information, which is referenced in {@link TypeDef}.
*
* @see TypeInfo
* @author Cause Chung
*/
public interface TypeDef extends Serializable {
String qualifiedName();

Expand Down
19 changes: 19 additions & 0 deletions internal/src/main/java/org/sharedtype/domain/TypeInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

import java.io.Serializable;

/**
* Type information.
*
* @see TypeDef
* @author Cause Chung
*/
public interface TypeInfo extends Serializable {
/**
* <p>Check if this type and its dependency types are resolved.</p>
* <p>
* When parsing a type's structure, a dependency type is firstly captured as a {@link TypeInfo}.
* At this stage, because we don't know its output structure or if it needs output at all, we mark it as unresolved.
* Also due to possible cyclic dependencies, the resolution stage needs to be performed after initial parsing state.
* During resolution, once a type is parsed, it's marked as resolved.
* Note that a type is marked as resolved when created, if it can be determined at that time.
* </p>
* <p>Object contains resolved flag as a mutable state</p>
*
* @return true is this type and its dependency types are resolved.
*/
boolean resolved();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import lombok.EqualsAndHashCode;
import lombok.Getter;

/**
* Represents a generic type variable.
*
* @author Cause Chung
*/
@Getter
@EqualsAndHashCode
@Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
final class JavaRecordIntegrationTest {
private final ClassDef classDef = (ClassDef)deserializeTypeDef("JavaRecord.ser");
private final ClassDef classDef = (ClassDef)deserializeTypeDef("org.sharedtype.it.java17.JavaRecord.ser");

@Test
void typeVariables() {
Expand Down
Loading