webcomponents / custom-elements-manifest-tools

Tools for working with custom elements manifests
BSD 3-Clause "New" or "Revised" License
8 stars 1 forks source link

[RFC/discussion] tools API design #2

Open 43081j opened 1 year ago

43081j commented 1 year ago

Copying most of this from my notes.

Motivation

We should provide the core functionality already duplicated across the various CEM projects in the wild.

Proposed design

It seems we need a few areas of utilities:

Type guards

Traversal functions

TBD

These traversal functions would be paired often with the type guards and assertion functions.

For example, find(package, null, (n) => isJavaScriptExport(n)).

Assertion functions

TBD

Getters

TBD

Prior art

CEM analyzer

CE language server

webcomponents.org

Open questions

Type guards

Traversals

cc @justinfagnani @matsuuu @rictic

justinfagnani commented 1 year ago

Thanks @43081j !

I think a first and high-level question we need to answer is what kind of package organization we want.

I can think of a few broad categories:

The first three categories may differer in scope/purpose, but should be environment agnostic. They could be three packages, or a single one. The lines could blur a bit: resolving references across manifests might require a loader. The validator could cleanly be a separate package, though it's not strictly necessary.

The next three would differ in dependencies and environments: a local loader might have Node-specific API requirements.

What I put up in #1 and #3 are separate environment-agnostic utilities package and a validator package, taken from the webcomponents.org work, but these could be re-arranged as we like...

43081j commented 1 year ago

i'd be tempted to do it the same way babel did

babel has @babel/traverse, @babel/types, @babel/parser, etc etc.

so in our case we'd have:

i guess my original post here is really the first two of those

Matsuuu commented 1 year ago

i'd be tempted to do it the same way babel did

babel has @babel/traverse, @babel/types, @babel/parser, etc etc.

so in our case we'd have:

  • traverse (utilities for find/get/etc of a manifest, incl traversing across multiple manifests)
  • type guards/assertions (utilities for asserting what type an arbitrary node is, and if it has particular properties, etc)
  • validation
  • manifest loaders (one package each)

I agree that this approach could work the best. A clear split between the packages for different use cases.

Wether the loader should be 2 packages or one, I don't know yet.

Having an API like typescript where you can create your own IO layer could work but at the same time, we could just write those 2 implementations ourselves since they will differ quite a lot

justinfagnani commented 1 year ago

I'm not sure what we really gain from separating traverse* from type guards. I don't see a downside to keeping them in on e package, but there is a downside to making too many packages - and of need future utilities that don't fit cleanly into traverse or types, requiring another one.

With the goal of separate loader packages being to divide the be environment requirements and dependencies, I think we need a spot for just the loader interface. That could go in its own package, or the general tools package.

Having an API like typescript where you can create your own IO layer could work but at the same time, we could just write those 2 implementations ourselves since they will differ quite a lot

This is the idea with the loader interface. Something like the WC catalog needs to load manifests from an online registry, a VS Code plugin needs to load it from disk.

43081j commented 1 year ago

you're right i think, so we should have a package that contains all the traversal/getters/assertions/etc.

which i guess is the tools package you created in the other PR.

the interface of that package is what im trying to define in the original post

justinfagnani commented 1 year ago

I just merged #1 and #3 that make separate validator and tools packages (though the validator package is empty), but I wonder if I should merge those and add the loader interface there, then I/O-specific packages can come next.

43081j commented 1 year ago

i feel like the validator package should stay separate, just to keep it focused.

though maybe "tools" might end up too generic? bit of a grey area as that package could easily end up bloated with random utils if we're not careful

bennypowers commented 1 year ago

I'd like an object oriented API that I could deliver to 11ty etempaltes:

<template webc:nokeep
          webc:for="declaration of 
                      cemPackageNameMap
                        .get(package)
                        .getDeclarationsForModule(module)">
  <cem-class webc:if="declaration.kind === 'class'" :@declaration="declaration"></cem-class>
  <cem-mixin webc:if="declaration.kind === 'mixin'" :@declaration="declaration"></cem-mixin>
  <cem-function webc:if="declaration.kind === 'function'" :@declaration="declaration"></cem-function>
  <cem-variable webc:if="declaration.kind === 'variable'" :@declaration="declaration"></cem-variable>
</template>