') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - Vanco/SequencePlugin: SequencePlugin for IntelliJ IDEA · GitHub
Skip to content

Repository files navigation

GitHub release

SequenceDiagram

Sequence Diagram is tool to generate simple sequence diagram(UML) from java, kotlin, scala(Beta) and groovy(limited) code. https://vanco.github.io/SequencePlugin.

with this plugin, you can

  • generate Simple Sequence Diagram.
  • Navigate the code by click the diagram shape.
  • Delete Class from diagram.
  • Export the diagram as image(SVG, JPEG, PNG, TIFF).
  • Export the diagram as PlantUML, Mermaid format file.
  • Exclude classes from diagram by Settings > Tools > Sequence Diagram
  • Smart Interface(experimental)
  • Lambda Expression(experimental)
  • Kotlin Support(Experimental)
  • Scala support(Experimental, Beta)
  • Groovy Support(Experimental, limited)

Experimental features

The experimental features created by myself, which is not part of UML standard. Use this feature in your own risk.

UAST support (since version 3.x)

SequenceDiagram version 3.x will use UAST api to generate sequence diagram.

Refer to 'The UAST description from IntelliJ Platform SDK'

UAST (Unified Abstract Syntax Tree) is an abstraction layer on the PSI of different programming languages targeting the JVM (Java Virtual Machine). It provides a unified API for working with common language elements like classes and method declarations, literal values, and control flow operators.

Which languages are supported?

  • Java: full support
  • Kotlin: full support
  • Scala: beta, but full support
  • Groovy: declarations only, method bodies not supported

Note : There are some limitation when generate from scala or groovy code. Refer to the list of known issues.

Smart Interface

Find the implementation of the interface smartly. e.g.

publicinterfaceFruit {
inteat();
}
publicclassAppleimplementsFruit {
@Overridepublicinteat() {
return5;
}
}

Apple implemented the Fruit interface. When we generate sequence diagram for the eatFruit method:

publicclassPeople {
privateFruitfruit = newApple();
publicvoideatFruit() {
fruit.eat();
}
}

I draw dummy implementation call in dash line.

Smart Interface

For the interface or abstract class, if there is only one implementation found, it will draw in diagram automatically. More than one implementation, you need to choose one to draw. this is an option in settings.

Lambda Expression

No standard for the lambda expression in the sequence diagram yet. So I create mine. e.g.

publicinterfaceService<Int, String> {
Stringinvoke(Inta);
}

I need draw the sequence diagram for hello method:

publicclassLambda {
publicService<Integer, String> hello() {
returna -> {
Fruitfruit = newApple();
fruit.eat();
return"I'm good!";
};
}
}

I draw a dummy () -> self call in diagram.

Lambda Expression

How to use

Sequence Diagram can generate sequence diagram from JAVA, Kotlin, Scala, Groovy File.

  1. Open Java/Kotlin/Scala/Groovy file
  2. Generate SequenceDiagram with shortcut Alt S for windows, Option S for macOS

Please try to experience it and find what happen.

Have fun!

Version History

Current Version

Version and API comparison

Open APIv2.x.xv3.x
IGeneratorSequenceGenerator
KtSequenceGenerator
UastSequenceGenerator
GeneratorFactoryJavaGeneratorFactory
KtGeneratorFactory
UastGeneratorFactory
ElementTypeFinderJavaElementTypeFinder
KtElementTypeFinder
ActionFinderJavaActionFinder
KtActionFinder
UastActionFinder
SequenceNavigableJavaSequenceNavigable
KtSequenceNavigable
JavaSequenceNavigable1

Function comparison

v2.x.x3.x
Language:
Java
Kotlin✓ Partial
Scala
Groovy✓ Partial
Entry:
Navigation Bar
Tools Menu
Editor Context Menu
Shortcut Alt S for windows
Option S for macOS
Project view popup menu
Structure view popup menu
Feature:
Smart Interface2✓ EXC: 2.2.4, 2.2.5
Smart Interface configuration
Lambda call configuration

versions history:

Changelog

Known issue

1. Scala for comprehension calls is not supported

For example:

classB() {
defbar() =Option("bar")
}
classA(b: B) {
deffoo() = {
valr="foo"+ b.bar().getOrElse("?")
r
}
deffoo2() = {
valr=for {
x <- b.bar()
} yield"foo"+ x
r.getOrElse("?")
}
}

the for comprehension call

valr=for {
x <- b.bar()
} yield"foo"+ x

it's UAST tree is UastEmptyexpression.

 UMethod (name = foo2)
UBlockExpression
UDeclarationsExpression
ULocalVariable (name = r)
UastEmptyExpression(type = PsiType:Option<String>)
UReturnExpression
UQualifiedReferenceExpression
USimpleNameReferenceExpression (identifier = r)
UMethodCall(name = getOrElse)
UIdentifier (Identifier (getOrElse))
ULiteralExpression (value = "?")

so the b.bar() method call will not generate base on UastEmptyexpression. Hopefully, the UAST api will solve this problem sooner.

2. Groovy method body is not supported

For example:

/** * A Class description*/classStudent {
/** the name of the person */String name
/** * Creates a greeting method for a certain person. * * @param otherPerson the person to greet * @return a greeting message*///known issue: groovy method will not generate in UASTStringgreet(StringotherPerson) {
"Hello ${otherPerson}"// call javaFruit fruit =newBanana()
fruit.eat()
}
}

Based on UAST api limitation, it's UAST tree is no method body mappings.

UFile (package = van.demo.grovvy)
UClass (name = Student)
UMethod (name = greet)
UParameter (name = otherPerson)

When generate sequence of method greet, the calls in the method body will not generate (the call java code in the body of greet).

"Hello ${otherPerson}"// call javaFruit fruit =newBanana()
fruit.eat()

Acknowledgement

Name history

Why change name?

Since 2011, I found a solution of NPE of original SequencePlugin, so I write email to Kentaur with my solution, He said he was not coding anymore. Instead, he sent me the code. I fix the NPE issue and publish to plugin repository with new name SequencePluginReload.

In 2015, the IntelliJ change the login system, and I lost my account, cannot continue to publish new version to the repository.

In 2016, I change the Name again to SequenceDiagram and host the source code on github. Now it is open source.

Thanks Kentaur for the great work on the original source.


Footnotes

  1. JavaSequenceNavigable work for Java, Kotlin, Scala, Groovy

  2. Smart interface will scan entire file and spend more generate time.

About

SequencePlugin for IntelliJ IDEA

Topics

Resources

Stars

695 stars

Watchers

21 watching

Forks

Releases

Packages

Used by

Contributors

Languages