gabotechs / dep-tree

Tool for helping developers keep their code bases clean and decoupled. It allows visualising a code base complexity using a 3d force-directed graph of files and the dependencies between them.
https://github.com/gabotechs/dep-tree
MIT License
1.5k stars 38 forks source link

Dart Language Parser #91

Open Attempt3035 opened 5 months ago

Attempt3035 commented 5 months ago

Working on a dart language parser! 🎉

Using regex and simple step by step process as I couldn't find a good way to handle the relative vs package absolute imports with participle, and a simple step by step regex should do everything that's needed.

Note: This is my first time using the go language, apologies for the many oversights I may make!

Current status:

gabotechs commented 5 months ago

Cool! Dart is a language that would be nice to have in dep-tree, I could even use it myself.

I see that the progress is still ongoing, let me know if you have any question along the process or if you want me to do a full review straight away.

Attempt3035 commented 5 months ago

Great! Thank you! Still definitely in prototype stage at the moment as I play around with it and wrap my head around go, but I'll definitely get you to have a further look a bit later down the track when I think it's working pretty properly! Quick question on exports though, firstly I don't really understand the role they play in the output entropy graph in languages like JS, secondly for dart to work properly I've been testing just treating exports as imports as they essentially import and re-export the file to be visible to other code when imported, doing this seems to make a correct output graph, what are your thoughts?

gabotechs commented 5 months ago

I don't really understand the role they play in the output entropy graph in languages like JS

Imagine that we have three files: a.js, b.js and c.js

// a.js
import { foo } from 'b'
// b.js
export { foo } from 'c'
// c.js
export const foo = 'foo'

Given this situation, what would you say, that a.js depends on b.js or c.js? This question can only be answered knowing which names where exported from which file, and in this case, foo is actually declared on c.js, not b.js. This logic is handled for you by dep-tree's machinery, but while implementing a new language, you need to at least provide which names are exported from which file.


for dart to work properly I've been testing just treating exports as imports as they essentially import and re-export the file to be visible to other code when imported, doing this seems to make a correct output graph, what are your thoughts?

I think Dart's implementation should be very straight forward, as the import system is very simple. You basically import whole files without declaring which names are imported, and there is already a function for building that kind of import: language.EmptyImport:

// EmptyImport builds an ImportEntry where nothing specific is imported, like a side effect import.
func EmptyImport(absPath string) ImportEntry {
    return ImportEntry{AbsPath: absPath}
}

You should be able to not even care about exports in Dart, as everything is exported by default, so you are pretty much always importing whole files instead of specific names.

Another approach you could take is to build imports with language.AllImport, but then you need to declare for each file which symbols are exported, so you will need to do a full parsing of each file declaring all the classes, functions, constants, types, etc... seems like a harder path

Attempt3035 commented 4 months ago

Thank you so much for the detailed explanation! (and apologies for my late response!) That's a lot clearer now! I've updated the imports as you suggested, which does indeed make more sense. I'm still wondering about the exports, in the example that:

// a.dart
import 'b.dart';

print(foo);
// b.dart
export 'c.dart';
export 'd.dart';
export 'e.dart';
export 'f.dart';
// c.dart
final foo = 'foo';

If we were to try to use the same logic as JS, really, a.dart only depends on c.dart but unless we parse everything, we have no way to know this. Assuming we don't want to parse everything (for now at least, maybe in the future when I've got a bit more time or staff willing to have a crack we can extend), from my understanding we have two options: