determining which packages a package exports

59 views
Skip to first unread message

Anders Holmgren

unread,
Jun 23, 2015, 11:20:56 PM6/23/15
to mi...@dartlang.org
As part of adding support for hosted packages to https://pub.dartlang.org/packages/jefe I need to be able to determine which packages a particular package exports so that I can set narrower dependency constraints on the pubspec

For example mojito exports many shelf packages. Currently I am generating these dependencies like

  shelf_auth: '^0.6.1'

  shelf_auth_session: '^0.4.2'

  shelf_bind: '^0.8.1'

  shelf_exception_handler: '^0.1.0'

  shelf_oauth: '^0.6.1'

  shelf_path: '^0.1.3'

  shelf_proxy: '^0.1.0+2'

  shelf_rest: '^0.2.0-beta.4'

  shelf_route: '^0.13.0-beta.3'

  shelf_static: '^0.2.2'


but these should be like


  shelf_auth: '>=0.6.1 <0.6.2'


etc


So I need some what to tell that mojito exports shelf_auth. Can analyzer tell me that? What's the best approach?


cheers

Anders

Bob Nystrom

unread,
Jun 24, 2015, 12:08:11 PM6/24/15
to General Dart Discussion
Oof, I don't know of any automated tooling for detecting this.

In general, you should be really careful if you export a library from some other package. Doing so couples you very strongly to that other package. You're basically delegating part of your own public API to another package.

In almost all cases, you don't want to do that.

Cheers!

- bob


--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Anders Holmgren

unread,
Jun 24, 2015, 4:44:56 PM6/24/15
to mi...@dartlang.org
Damn, I feared as much. I guess I could always do a kind of grep for it in the lib dir of the package :/

Well I hope I am using 'export' for good. I use it in the following two places.

1/ in the new version of shelf_rest. I've reworked shelf_rest so that it is now a drop in replacement for shelf_route. 
Previously you imported both packages and plugged shelf_rest into shelf_route. Now you import shelf_rest instead of shelf_route and you get all the functionality of shelf_route plus mirror & annotation magic to reduce boilerplate.

I expect 90% of users / use cases to simply use shelf_rest, but for those wary of mirrors or those that want to use it client side, then shelf_route is the better option.

2/ in mojito. Mojito is a thin framework that bundles many shelf packages and provides a fluent-ish api over them. 

It contains a router that is a drop in replacement for shelf_rest. It adds some methods like

router.addStaticAssetHandler('ui')

and

router.addOAuth2Provider(....)


that create routes based on some of the bundled packages (shelf_static and shelf_proxy in the first method, shelf_oauth in the second).

The idea again is that users simply import mojito instead of shelf_rest, shelf_auth, shelf_oauth, shelf_xxx

I would expect that 91.3% of users would import mojito in place of shelf_rest and the other shelf_xxx. (Disclaimer: it is possible that my maths is a little dubious)

So these cases are both about making it easier for the users. I hope / believe this is a 'good' use of export

Don Olmstead

unread,
Jun 24, 2015, 4:51:45 PM6/24/15
to mi...@dartlang.org
Yea its not really clear when its a good idea to export a dependency. Suggested this be fleshed out in an article https://github.com/dart-lang/www.dartlang.org/issues/1349

Natalie Weizenbaum

unread,
Jun 24, 2015, 5:18:58 PM6/24/15
to General Dart Discussion
You can certainly do better than grepping. The analyzer provides access to imports and exports (and even has a special API for parsing them quickly), and it wouldn't be that difficult to write some code that looks at all the public library files and traverses exports to find the total set of exported packages. There's some code similar to this in pub (albeit not export-specific) for determining whether transformers have dependencies on one another.

Anders Holmgren

unread,
Jun 24, 2015, 5:22:46 PM6/24/15
to General Dart Discussion
Thanks Natalie. That sounds much cleaner. I'll look into the analyzer package. I haven't used the analyzer package yet so might take me a little to get my head around

Anders Holmgren

unread,
Jun 25, 2015, 9:50:24 PM6/25/15
to mi...@dartlang.org
Thanks for the pointer, turned out to be really easy in the end with the analyzer package

  CompilationUnit get compilationUnit {
    final mainLibraryPath =
        p.join(installDirectory.path, 'lib', '${name}.dart');
    return parseDartFile(mainLibraryPath);
  }

    Iterable<String> get exportedDependencyNames {
    final exports =
        compilationUnit.directives.where((d) => d is ExportDirective);

    final exportedPackageNames = exports
        .map((exp) => exp.uri.stringValue)
        .where((uri) => uri.startsWith('package:'))
        .map((String uri) => uri.substring('package:'.length, uri.indexOf('/')))
        .toSet();

    return pubspec.dependencies.keys
        .where((n) => exportedPackageNames.contains(n));
  }

Reply all
Reply to author
Forward
0 new messages