Code Monkey home page Code Monkey logo

tplant's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

tplant's Issues

RayTracer parser test fails.

When running the npm test script the RayTracer parser test fails.

  Parser
    ✓ generate plantuml for Classes/Greeter.ts (970ms)
    ✓ generate plantuml for Inheritance (568ms)
    ✓ generate plantuml for Abstract/AbstractClass.ts (410ms)
    1) generate plantuml for RayTracer


  3 passing (2s)
  1 failing

  1) Parser
       generate plantuml for RayTracer:

      AssertionError [ERR_ASSERTION]: '@startuml\n@enduml' == '@startuml\nclass Vector {\n    +x: number\n    +y: number\n    +z: number\n    +{static} times(k: number, v: Vector): Vector\n 
      + expected - actual

It seems like nothing is being generated for RayTracer.

How do we use it in WebStorm? :)

Hey Brian,

I landed new from that other issue thread we were going back and forth in. I'm excited to try this out and get done actual uml diagrams for my Angular 2 projects. I'd also be willing to help add to the README once I get it working. thanks. :)

Error > throw new Error('unable to determine member type'); on file.ts

Hi, I get errors. I am using Node 12 on Linux.

Should this file work? Thanks!:

$ npx tplant --input game-object.ts > app.puml
/home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:171
                throw new Error('unable to determine member type');
                ^

Error: unable to determine member type
    at getMemberType (/home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:171:23)
    at getMemberReturnType (/home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:96:26)
    at serializeMember (/home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:84:25)
    at /home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:236:36
    at Map.forEach (<anonymous>)
    at serializeInterface (/home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:235:24)
    at visit (/home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:56:25)
    at visitNodes (/home/david/sites/testuml/node_modules/.registry.npmjs.org/typescript/3.4.5/node_modules/typescript/lib/typescript.js:16514:30)
    at Object.forEachChild (/home/david/sites/testuml/node_modules/.registry.npmjs.org/typescript/3.4.5/node_modules/typescript/lib/typescript.js:16742:24)
    at /home/david/sites/testuml/node_modules/.registry.npmjs.org/tplant/2.0.4/node_modules/tplant/dist/generateDocumentation.js:30:34

on game-object.ts:

export type Vector2 = [number, number];

export const vectors = {
  add(a: Vector2, b: Vector2): Vector2 {
    return [a[0] + b[0], a[1] + b[1]];
  },
  multiply(a: Vector2, b: Vector2): Vector2 {
    return [a[0] * b[0], a[1] * b[1]];
  },
  get up(): Vector2 {
    return [0, 1];
  },
  get down(): Vector2 {
    return [0, -1];
  },
  get left(): Vector2 {
    return [-1, 0];
  },
  get right(): Vector2 {
    return [1, 0];
  },
};

/**
 * =============================================================================
 * GameObject (modified https://docs.unity3d.com/Manual/class-Transform.html)
 * =============================================================================
 */
interface GameObjectOptions {
  position: Vector2;
  rotation?: number;
  scale?: Vector2;
}

export abstract class GameObject {
  public position: Vector2;
  public rotation?: number;
  public scale: Vector2;

  public constructor({
    position,
    rotation = 0,
    scale = [1, 1],
  }: GameObjectOptions) {
    this.position = position;
    this.rotation = rotation;
    this.scale = scale;
  }
  public static createCharacters<T>({ ...options }: GameFactoryOptions): T[] {
    let character: Character;
    const characters = [];

    for (let index = 0; index < options.numberOf; index += 1) {
      switch (options.Character) {
        case Hero:
          character = new options.Character({
            position: options.positionFn(),
            widthHeight: [50, 25],
          });
          break;

        case Zombie:
          character = new options.Character({
            position: options.positionFn(),
            widthHeight: [50, 25],
            image: options.image,
            // velocity: [1, 1],
          });
          break;

        case Bullet:
          character = new options.Character({
            position: options.positionFn(),
            widthHeight: [5, 25],
            rotation: [10, 10],
          });
          break;

        default:
          break;
      }
      characters.push(character);
    }

    return characters;
  }
}

/**
 * =============================================================================
 * Character
 * =============================================================================
 */
interface CharacterOptions extends GameObjectOptions {
  alive?: boolean;
  velocity?: Vector2;
  widthHeight: Vector2;
}

abstract class Character extends GameObject {
  public alive: boolean;
  public velocity: Vector2;
  public widthHeight: Vector2;
  public abstract imageType: string; // 'bitmap' | 'rectangle';

  public constructor({
    alive = true,
    velocity = [0, 0],
    widthHeight,
    ...characterOptions
  }: CharacterOptions) {
    super(characterOptions);
    this.alive = alive;
    this.velocity = velocity;
    this.widthHeight = vectors.multiply(widthHeight, this.scale);
  }
}

/**
 * =============================================================================
 * Hero
 * =============================================================================
 */
export class Hero extends Character {
  private color = 'red';
  public imageType = 'rectangle';

  public constructor({ ...characterOptions }: CharacterOptions) {
    super(characterOptions);
  }
}

/**
 * =============================================================================
 * Zombie
 * =============================================================================
 */
interface ZombieOptions extends CharacterOptions {
  image: HTMLImageElement;
}

export class Zombie extends Character {
  private image: HTMLImageElement;
  public imageType = 'bitmap';

  public constructor({ image, ...characterOptions }: ZombieOptions) {
    super(characterOptions);
    this.image = image;
  }
}

/**
 * =============================================================================
 * Bullet
 * =============================================================================
 */
export class Bullet extends Character {
  private color = 'green';
  public imageType = 'rectangle';

  public constructor({ ...characterOptions }: CharacterOptions) {
    super(characterOptions);
  }
}

/**
 * =============================================================================
 * Game simple factory pattern
 * =============================================================================
 */

export interface Newable<T> {
  new (...args: any[]): T;
}

interface GameFactoryOptions {
  Character: Newable<Character>; // https://stackoverflow.com/questions/41017287/cannot-use-new-with-expression-typescript
  numberOf: number;
  level: number;
  positionFn: any;
  image?: HTMLImageElement;
}

Handle ECONNRESET on image file request.

I/O

In:

npx tplant --input ./**/*.ts --output ./Playground.svg

Out:

npx: installed 15 in 3.177s
events.js:292
      throw er; // Unhandled 'error' event
      ^

Error: socket hang up
    at connResetException (internal/errors.js:607:14)
    at Socket.socketOnEnd (_http_client.js:493:23)
    at Socket.emit (events.js:327:22)
    at endReadableNT (internal/streams/readable.js:1327:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
Emitted 'error' event on ClientRequest instance at:
    at Socket.socketOnEnd (_http_client.js:493:9)
    at Socket.emit (events.js:327:22)
    at endReadableNT (internal/streams/readable.js:1327:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21) {
  code: 'ECONNRESET'
  

It is clear that this is not a mistake on your part. However, it would be nice to write something meaningful in addition to the log.

Proposed solution:

  1. Check URL maxlength and assert (414 Request-URI Too Large).
    path: `/plantuml/${extension}/${encode(input)}`
  2. Handle ECONNRESET or add description about diagram size.

Add support for an !include file (optional) that would have settings

I want to use this in a CI on Github to create PlantUML documentation of my API. But I don't want to see all the methods or attributes in the diagrams.
I'd like to insert a line hide members. But maybe I also want to hide circle or other customizations. I don't want to hack something with sed (but I will probably end up doing that).

It would be cool if tplant had an option -config <includefile> that would include the file just after the @startuml that is generated.

svg file (or puml file) only contains one box

E.g.

tplant --input test/Playground/Inheritance/*.ts --output test/Playground/Inheritance.svg

results in a single box, that describes the Animal class.

tplant --input test/Playground/Inheritance/*.ts --output test/Playground/Inheritance.puml

results in:

@startuml
class Animal {
+name: string
+move(distanceInMeters?: number): void
}
@enduml

Presumably there should be other boxes, such as Horse.

Running on Win 10, via MINGW64 git-bash terminal window.

Problem when interfaces are in a different namespace

tplant version: 3.1.1

Problem when the interface is in a different namespace, when using in a class or in an interface, the svg is not generated. Below, the svg "content":
image

Cause I was able to replicate the problem with the code below:

namespace interfaces {
  export interface IGreeter {
    greet(): string;
  }
}

export class Greeter implements interfaces.IGreeter {
  greeting: string;
  prefix: string = "Hello, ";
  constructor(message: string) {
    this.greeting = message;
  }
  set prefix(prefix: string) {
    this.prefix = prefix;
  }
  greet(prefix: string = "Foo"): string;
  greet(): string {
    return this.prefix + this.greeting;
  }
}

undefined and null types aren't transformed properly

Code example:

interface ComplexTypesInterface {
    type: Dict<{ stringType: string; numberType: number; }> | undefined;
}

Current transformation:

@startuml
interface ComplexTypesInterface {
    type: Dict<{ stringType: string; numberType: number; }>
}
@enduml

Expected transformation:

@startuml
interface ComplexTypesInterface {
    type: Dict<{ stringType: string; numberType: number; }> | undefined
}
@enduml

Namespaces not supported?

Great work, I'm eager to use it!

I'm working on a large browser based project with namespaces. It looks like tplant outputs only the startuml and enduml tags when hitting the keyword namespace or module,..

Not showing all relationships

I am trying to run your project on this repo

The command i am running is tplant --input **/*.ts --output Playground.svg --project /

The output i get is this:
image

Surely i should see many more relationships than this? Am i doing something wrong?

Cooperation with plantuml-parser?

I am the maintainer of tplant ^ -1 or in other words plantuml-parser 😃 . I do think it would be very beneficial for users if we could somehow make our two projects compatible with each other. Meaning if code could be transpired to a diagram using tsplant and then back to code using plantuml-parser.

In this issue i would just like to check if you'd see value in a collaboration. And maybe discuss possible next steps.

Support for type parameters.

The tplant does not support type parameters. Therefore, when the following code was used:

class NodeDependenciesProvider implements vscode.TreeDataProvider<Dependency> {
...

The PlantUML output did not include the type information behind the implements keyword:

@startuml
class NodeDependenciesProvider implements  {
    +getTreeItem(element: Dependency): vscode.TreeItem
    +getChildren(element?: Dependency | undefined): Thenable<Dependency[]>
}
...
@enduml

And in preview window I got this error
Screenshot 2023-06-09 at 16 22 28

Error: Unable To Determine Member Modifier Type

When I run:
./bin/tplant.js -i ~/Git-Projects/t2-2/t2/CypherApp/src/app/app.component.ts

I now get this error:

/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:154
        throw new Error("unable to determine member modifier type");
        ^

Error: unable to determine member modifier type
    at getMemberModifierType (/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:154:15)
    at serializeMember (/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:72:27)
    at serializeClass (/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:209:34)
    at visit (/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:47:25)
    at visitEachNode (/Users/jameslynch/Git-Projects/tplant/node_modules/typescript/lib/typescript.js:13907:30)
    at Object.forEachChild (/Users/jameslynch/Git-Projects/tplant/node_modules/typescript/lib/typescript.js:14078:24)
    at generateDocumentation (/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:27:16)
    at module.exports (/Users/jameslynch/Git-Projects/tplant/src/typescriptToMeta.js:230:12)
    at Object.<anonymous> (/Users/jameslynch/Git-Projects/tplant/bin/tplant.js:19:5)
    at Module._compile (module.js:570:32)
tplant (master) ♘ 

Please add abstract fields

Hi,

At the moment tplant does not add {abstract} fields when needed. For example:

abstract class BitmapCharacter extends BaseCharacter {
  abstract image: HTMLImageElement;
  abstract widthHeight: Vector2;
}

should generate:

abstract class BitmapCharacter extends BaseCharacter {
    +{abstract} image: HTMLImageElement
    +{abstract} widthHeight: [number, number]
}

Which makes them italic in the diagram, much easier to understand :) Cheers.

How to use project option?

Hi! I have tried using project option, but cannot get it to work.

I always get "Missing input file"

Any clues?
I have tested with a simplified tsconfig (just files, one path).
No joy.

BR! /marcus

Put class accessors together with methods

Wouldn't it be better to have class accessors together with it's methods? That would make diagram easier to read.

class Accessors {
  _foo: string
  _bar: string

  get bar() {
    return this._bar
  }

  set bar(value) {
    this._bar = value
  }

  foo() {
    this._foo = 'foo'
  }
}

current output

Screenshot 2023-10-01 at 14 33 50
@startuml
class Accessors {
    +_foo: string
    +_bar: string
    +bar: string
    +bar: string
    +foo(): void
}
@enduml

suggestion

Screenshot 2023-10-01 at 14 32 12
@startuml
class Accessors {
    +_foo: string
    +_bar: string
    +{method} get bar: string
    +{method} set bar: string
    +foo(): void
}
@enduml

Generate/Download plantuml image

Add the feature to generate/download the platuml generated image. The url can be generated with plantuml-encoder
Suggestion:
Read the extension from the output file given like:

tplant -i sample/Classes/Greeter.ts -o Greeter.svg
tplant -i sample/Classes/Greeter.ts -o Greeter.png

For a better experience, we might need to accept multiple outputs for this case.

Error with version 2.1.5

The recent commit 2 days ago (as of this writing) cb68f529491dabda19fe9e2ff3284ad80e8b2b30 has a bug which leads to the following error upon trying to use tplant anything.

internal/modules/cjs/loader.js:605
    throw err;
    ^

Error: Cannot find module './components/Class'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:603:15)
    at Function.Module._load (internal/modules/cjs/loader.js:529:25)
    at Module.require (internal/modules/cjs/loader.js:659:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (C:\Users\Administrator\AppData\Roaming\npm\node_modules\tplant\dist\convertToPlant.js:11:15)
    at Module._compile (internal/modules/cjs/loader.js:723:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:734:10)
    at Module.load (internal/modules/cjs/loader.js:620:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
    at Function.Module._load (internal/modules/cjs/loader.js:552:3)

Installing version 2.1.4 fixes the issue.

OS: Windows 10 64-bit Version: 1803. Build: 17134.81
NPM: 6.4.1
Node: 11.4.0

[Feature] Support TSX files and create diagrams for React components

Opening this issue to request support for TSX files and to create class diagrams for React components.

Main goals

  • Be capable of parsing TSX files to extract normal typescript constructs like types, interfaces, and classes
  • Recognize when a class or a function is a React component and produce different output for those
  • Optionally extract the props and state types for a React component and include them in the output

Caveats:

  1. React components do not have to be named, and are often exported as a default const arrow function:
export default (props: SomePropsType) => {
    return <div />
}

For these, I think it would make sense to use the file name as the component's name, unless the filename is "index.tsx", in which case the containing folder's name should be used. This should cover 99.9% of use cases.

  1. If a component is in the form const ComponentName = (props: SomePropsType) => <div />;, then the const variable's name should be used as the component name.

  2. With react hooks, it is not possible to determine a hooks-based component's state. We can just ignore the state in these cases. If better tooling arises in the future for this from the react team (or a 3rd party), this could be revisited

export default () => {
    // Not easy at all to infer these types, especially with custom hooks
    // that wrap multiple calls to useState
    const [counter, setCounter] = useState(0);

    return (
        <div>
            <h1>Count: {counter}</h1>
            <button onClick={() => setCounter(counter + 1)}>+</button>
            <button onClick={() => setCounter(counter - 1)}>-</button>
        </div>
    );
}

Example

Input:

interface FCProps {
    text: string
}
function FuncComp(props: FCProps) {
    return <span>{props.text}</span>;
}

interface ArrowProps {
    title: string;
    value: number;
}
const ArrowComp = (props: ArrowProps) => {
    return (
        <div>
            <FuncComp text={props.title} />
            <span>Value: {props.value}</span>
        </div>
    );
}

const NoPropsComp = () => {
    return (
        <div>
            <span>I don't have any props</span>
        </div>
    );
}

interface ClassProps {
    title: string;
}

interface ClassState {
    value: number;
}

// Props and state types can be left out here, but it has to be
// given if they're being used.
class ClassComp extends React.Component<ClassProps, ClassState> {
    state = {
        value: 0,
    };

    public render() {
        return (
            <div>
                <ArrowComp
                    title={this.props.title}
                    value={this.state.value} 
                />
                <NoPropsComp />
                <button onClick={this.onIncrement}>+</button>
                <button onClick={this.onDecrement}>-</button>
            </div>
        );
    }

    private onIncrement = () => {
        this.setState(prevState => ({ value: prevState.value + 1 }));
    }

    private onDecrement = () => {
        this.setState(prevState => ({ value: prevState.value - 1 }));
    }
}

Output:

@startuml
class FuncComp <function> {
  ..Props..
  text: string
}
class ArrowComp <arrow> {
  ..Props..
  title: string
  value: number
}
class NoPropsComp <arrow> {
  ..Props..
}
class ClassComp <class> {
  ..Props..
  title: string
  ..State..
  value: number
}

ClassComp <-- ArrowComp
ClassComp <-- NoPropsComp
ArrowComp <-- FuncComp
@enduml

image

Not addressed

  1. React Context - it may be possible to extract the React context type from class components that use them, as it's specified as
class MyComp extends React.Component {
    contextType: React.ContextType<typeof MyContext>
}

but that seems out of scope for this initial issue, and becomes more complicated with hooks.

  1. Component diagrams could become incredibly large. It is typical for React projects to have a lot of components defined in them. Maybe support a --max-component-depth option or something to work around it?

  2. This would ignore any components that are made using React.createElement, but no one really does that anymore.

  3. Doesn't address how to handle 3rd party components. I'd say ignore them. 3rd party components are often written in JS and shipped with .d.ts files. This would be very difficult to support, and probably wouldn't be very useful anyway.

Not representing relation when class is in a different namespace

Version tplant: 3.1.1

Problem when a class is in a different namespace, the relation to that class is not represented.

Cause

namespace classes {
  export abstract class AbstractPrefix {
    abstract prefix: string;
  }
}

export class Greeter extends classes.AbstractPrefix {
  greeting: string;
  prefix: string = "Hello, ";
  //... rest of the sample
}

Output
image

Expected output
image

Add the abbiliy to exclude path

Hi,

It could be great to add an option to exclude Typescript files.

Example :
tplant --input src/**/.ts --output uml/uml.svg --associations --exclude src/extensions/.ts

My use case is that I have created extensions for some class in the src/extensions/* folder and plantuml does not support that. I would like to exclude all the files in this folder and keep all other files contains in src/**/*.ts to generate the uml.

Problems with composition feature

First, thanks for making tplant! It is very useful!

The composition flag is good, but I'm suggesting the following improvements. Let me use this example from test/Raytracer/Scene.ts:

export interface Scene {
    things: Thing[];
    lights: Light[];
    camera: Camera;
}

The PlantUML produced using the composition flag should be

Scene --> "things" Thing
Scene --> "lights" Light
Scene --> "camera" Camera

Here are my reasons:

  • it should default to a simple association, because it's wrongly showing all associations as whole/part (composition, i.e., *--), many of which are not truly the semantics of composition. It's pretty hard to figure that out from static analysis of source code, I think. Edit: Furthermore, aggregation (to many) isn't really any different than an association in UML, so a simpler link is just to use --.
  • it could/should include navigability, since you can see it from the TypeScript code, e.g. Scene.things: Thing[]; implies one can navigate from the class Scene to one or more Thing. Edit: Hence, I suggest -->.
  • it could contain cardinalities on the association. However, PlantUML has trouble to show both the names of the ends, e.g., "things" Thing as above, and a cardinality such as "*" Thing. Maybe combining them?
Scene --> "things\n*" Thing

which doesn't always look so great, but is useful I think.

Edit: in cases of a single reference, e.g. myThing: Thing the cardinality would be "1"

I'd be happy to try a PR to support some of these things (with tests, of course), if you think they're reasonable.

Not working, just error messages

If I install globally or locally via NPM I just get:

/usr/bin/tplant: line 1: use strict: command not found
/usr/bin/tplant: line 2: syntax error near unexpected token `('
/usr/bin/tplant: line 2: `var __importDefault = (this && this.__importDefault) || function (mod) {'

If I just type tplant or use tplant --input app.ts --output uml.puml

version 2.2, Fedora 29 Linux, Node 12.1.0
(an older version of tplant worked fine, I filed another issues a while ago)

Enum empty in plantuml

Thanks for this :) !

I've an issue with enum when I use tplant the enum is empty.

cat MySuperEnum.ts

export enum MySuperEnum {
  AWESOME,
  SUPER,
  COOL
}

npx tplant --version

2.0.3

npx tplant --input MySuperEnum.ts

@startuml
enum MySuperEnum {
}
@enduml

overloaded methods/functions are exported incorrectly

I know overloading is a rather rare (and kinda hacky) thing in Typescript, but still a thing that exists. At the moment, those functions will be exported incorrectly by tplant.

Example ts

export class Test {
	move(dx: number, dy: number): string;
	move(v: Vector2): string;
	move(vordx: number | Vector2, dy?: number): string {
		return "just a test";
	}
}
export class Vector2{
	public x: number;
	public y: number;
}

What it currently looks like

@startuml
class Test {
    +move(): dx: number, dy: number): string; (v: Vector2): string; }
}
class Vector2 {
    +x: number
    +y: number
}
@enduml

What it should look like

@startuml
class Test {
    +move(dx: number, dy: number): string
    +move(v: Vector2): string
}
class Vector2 {
    +x: number
    +y: number
}
@enduml

Problem parsing namespaces

Problem
When a namespace defines several namespaces, the output file is just the first namespace, and everything else is ignored.

Scenario
Imagine defining a namespace that contains other namespaces until it has the class:

namespace very.special {
  export class Greeter {
    greeting: string;
    prefix: string = "Hello, ";
    constructor(message: string) {
      this.greeting = message;
    }
    set prefix(prefix: string) {
      this.prefix = prefix;
    }
    greet(prefix: string = "Foo"): string;
    greet(): string {
      return this.prefix + this.greeting;
    }
  }
}

When running the command line:
tplant --input test/Playground/Classes/*.ts --output test/Playground/testmultinamespace.svg

The output is the following:
image

All the code that is analyzed before this pattern gets added to the SVG, but after this pattern, nothing else is added.

Generic Types don't generate compositions

Example:

interface GenericTypes {
    genericType: GenericClass<string, number>;
    genericType2: GenericClass2<string>;
    genericReturnType(): GenericInterface<string>;
    genericReturnType2(): GenericInterface3<string, number>;
    genericParameter(parameter: GenericInterface2<string>): void;
}

Current behavior:

@startuml
interface GenericTypes {
    +genericType: GenericClass<string, number>
    +genericType2: GenericClass2<string>
    +genericReturnType(): GenericInterface<string>
    +genericReturnType2(): GenericInterface3<string, number>
    +genericParameter(parameter: GenericInterface2<string>): void
}
@enduml

Expected behavior:

@startuml
interface GenericTypes {
    +genericType: GenericClass<string, number>
    +genericType2: GenericClass2<string>
    +genericReturnType(): GenericInterface<string>
    +genericReturnType2(): GenericInterface3<string, number>
    +genericParameter(parameter: GenericInterface2<string>): void
}
GenericTypes *-- GenericClass
GenericTypes *-- GenericClass2
GenericTypes *-- GenericInterface
GenericTypes *-- GenericInterface3
GenericTypes *-- GenericInterface2
@enduml

creating one plantuml for the whole project

Hi. This might be a big noob question, thanks for your help in advance.
I am creating a new ionic project which uses Typescript and am now trying to generate a UML diagram of all the pages and services I have in my project.
basically, I have 4 pages, each page have a .ts file which all imports one ts file called orgService.ts. When I use this orgService.ts as input, the uml generated only shows the orgService and files the orgService.ts imports, but not ones that import orgService.ts. How do I have all of them in a single uml diagram?

Thanks for the help again :)

Support TS Utility Types

TypeScript provides several utility types to facilitate common type transformations. These utilities are available globally.

interface Todo {
  title: string;
  description: string;
  completed: boolean;
  createdAt: number;
}

class MyTodo implements omit<Todo, "createdAt"> {
…
}

Utility Types should be considered in the presentation of the class diagrams. Currently, they are incorrectly listed as independent instances.

Missing Aggregation/Composition feature

Hi! First of all I would like to express great admire to this idea.

It's so simple and implementation is perfect.

However I would like to have some feature which I wish to have in my diagram.

Sometimes we have classes which have instances of another classes. So it's not inheritance but another way of relationship.

How about the idea to invent pseudo comment (may be TSDoc) in ts file declaring that a specific attribute is a relationship in fact: aggregation or composition? Or at least by default all kinds of attributes with references to interfaces/classes include with aggregation by default?

Thank you!

Use custom tsconfig

Now, we always use an default configuration.

options: ts.CompilerOptions = {
    module: ts.ModuleKind.CommonJS,
    target: ts.ScriptTarget.ES2015
}

It can change from project to project, so we should be able to define an custom tsconfig.json file for the compiler.

Like:

tplant -i Foo/Bar.ts --tsconfig Foo/tsconfig.json

Broken output if multiple exports in same nested file

If a nested folder has a file with multiple named exports the output class name gets broken.

// /FooBar/types.ts

export interface Foo {
  bar: number
  foo: string
}

export interface Bar extends Foo {
  foobar: boolean
}

run in root folder: npx tplant -A -f mermaid -i '**/*.ts' -o uml.mmd

Output:

classDiagram
class Foo {
    +bar: number
    +foo: string
}
<<Interface>> Foo
"FooBar/types".Foo <|.. Bar
class Bar {
    +foobar: boolean
}
<<Interface>> Bar

Expected:

classDiagram
class Foo {
    +bar: number
    +foo: string
}
<<Interface>> Foo
Foo <|.. Bar
class Bar {
    +foobar: boolean
}
<<Interface>> Bar

Both Mermaid and PlantUML break because of "FooBar/types".

Version: 3.1.2

Handle indexes

Handle indexes. Example:

interface Dict<T> {
    [index: string]: T;
}
@startuml
interface Dict<T> {
    +[index: string]: T
}
@enduml

Error: read ECONNRESET

PS C:\victor-web\victor-next\apps\victor-next> tplant --input "./src/victor-next/controls/oneUp/*.ts" --output test.svg
events.js:291
throw er; // Unhandled 'error' event
^

Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:209:20)
Emitted 'error' event on ClientRequest instance at:
at Socket.socketErrorListener (_http_client.js:427:9)
at Socket.emit (events.js:314:20)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read'
}
PS C:\victor-web\victor-next\apps\victor-next>

Broken .png files.

Hi,

Today I tried to create a .png file twice and both times they came back corrupted and unable to display. File length 111.2 kB. The .svg is still working fine.

"uml": "tplant --input src/app.ts --output uml-diagram.png"

( tplant --version 2.3.0 )

Silent failure when output directory does not exist

Hi, great library.
A small issue I ran into, is that tplant will not throw an error/warning when the output directory does not exist. It simply says Done in x secs. while nothing is generated.

In my case, I wanted to output to reports/uml/uml.svg. reports/uml did not exist, reports/xyz did, though.

Suggested solution:

  1. Generate output directory if not exists
  2. Warn/error when output dir could not be created.

Cheers

Error: Cannot find module 'commander'

Hi, I just cloned this repo and tried to run this command:

./tplant.js ../sample/Class.ts

but I'm getting this error:

module.js:471
    throw err;
    ^

Error: Cannot find module 'commander'
    at Function.Module._resolveFilename (module.js:469:15)
    at Function.Module._load (module.js:417:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/jameslynch/Git-Projects/tplant/bin/tplant.js:3:15)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)

Can't extends multiple interfaces

Hello! I encountered a problem when generating diagram.

Example content-object.model.ts:

export interface ContentObject extends PageOption, BaseContentModel {
  id: number;
  type: string;
  name: string;
  label: string;
}

When I produce the UML file, there should have be two extend arrows (Pageoption and Basecontentmodel) but it only had one to PageOption interface.

Results in

ContentObject ⇒ PageOption

tplant 3.1.0 doesn't support Typescript 4.7's "moduleResolution": "Node16"

Describe the bug

  • Node.js version: 16.15.0
  • OS & version: Windows 11

Actual behavior

Using tplant CLI with Typescript 4.7 and moduleResolution="Node16" raises the following error:

   Error: Argument for '--moduleResolution' option must be: 'node', 'classic', 'node12', 'nodenext'.

Code to reproduce

package.json

{
  "name": "tplant-node16-bug",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "uml": "tplant -i src/**/*.ts -o diagram.puml"
  }
  "devDependencies": {
    "tplant": "^3.1.0",
    "typescript": "^4.7.4"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "module": "Node16",
    "moduleResolution": "Node16",
    "target": "es6",
  },
  "exclude": [
    "node_modules"
  ]
}

"moduleResolution": "Node16" is required for Typescript 4.7 support of the exports field in package.json

Doesn't understand default exports

Just ran tplant on my project, got strange results. It doesn't seem to understand that default is a keyword, and not the name of the class. Here are some examples:

class default extends Error {
class default {
class default extends Client
class default {
abstract class default {
class default extends Parser {

And so on.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.