-
-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Have you checked for existing feature requests?
- Completed
Summary
Hey, it's me, out here filing an issue against an obscure package whose existence might be unknown to anyone but me.
This package is what does the work of matching up service providers with service consumers. It does that job quite well — in part due to the simplicity of the implementation. Even though Pulsar uses service-hub largely within the context of connecting one package's main module to another's, service-hub itself works on a more basic level: a service can be any sort of object. It's in Pulsar's Package source code that we add ritual around how services are exposed and consumed.
The problem is in how difficult it is to introspect which packages provide and consume services.
For instance: I implemented a Symbols View: Show Active Providers command so that a user could see a list of packages that acted as providers for the symbol.provider service. I could've done something like this…
atom.packages.serviceHub.consume('symbol.provider', '^1.0.0', (results) => {
console.log(results.map(r => r.packageName));
});…but that only works because packageName is part of the service definition.
Let's try it with a service whose contract I didn't define, like code-format.onSave…
atom.packages.serviceHub.consume('code-format.onSave', '0.1.0', (results) => {
console.log(results);
});
// [{
// formatOnSave: function () { … },
// priority: 1,
// grammarScopes: ['source.ts', 'source.tsx', 'source.js']
// }]…and you see the problem. If metadata isn't part of the service definition, then you've just got a bunch of services and you don't really have any idea where they came from.
This could possibly be solved in Pulsar itself solely by introducing new conventions around service-hub, but I'm opening this ticket just as an exploration of a different idea: to allow each provided or consumed service to define arbitrary metadata that travels alongside the service object. This metadata would have no schema; it would just be a mechanism that could be used according to whatever conventions the user wanted.
What benefits does this feature provide?
This is something I'm interested in fixing because I suspect the “hidden” nature of services is a point of confusion. We generally explain that a package like autocomplete-plus relies on other packages to supply it suggestions, but it wouldn't surprise me if the average Pulsar user didn't have much of a mental model for why or how this works — or where to start to address it if it stopped working.
This is more pressing of a need in situations where there are multiple providers of a service and a consumer has to pick one. Just as autocomplete-plus does, most Atom IDE services handle this by having each provider define a priority. That's fine, but ideally the user understands this system well enough to know what to do to change the ordering if needed.
In our code-format.onSave example, they might discover that there are two service objects that claim to be able to format TypeScript files; that one defines a priority of 1 and the other defines a priority of 100. Where did they come from? It's anyone's guess.
Any alternatives?
The alternative is generally what I've been doing: making package metadata an explicit part of the service contract. As far as I know, symbol.provider is the first service to require a packageName property within the contract.
This is a tall task, though, because it would necessitate revisiting a bunch of services — particularly those defined by Atom IDE a long time ago — and adding the same metadata to each contract. This would require a version bump for each service and would not be backward-compatible.
The upside of this proposal is that it's a way to capture information we already have in a backward-compatible way.
Other examples:
No response