[labs/analyzer] Don't export (most) helper methods, refactor onto model classes#3254
[labs/analyzer] Don't export (most) helper methods, refactor onto model classes#3254kevinpschaaf merged 6 commits intomainfrom
Conversation
Fixes #3235 by ensuring that consumers of an analyzer model don't use incompatible helper methods (due to instanceof, caching, etc.) from a separate installation of the analyzer library. Restricts package exports to index.js, and only exports the Analyzer class + types (and select cross-package-safe helpers). Helpers like `isLitElementDeclaration` and `getModulesWithDeclarations` are now class methods on model classes, rather than standalone module exports.
🦋 Changeset detectedLatest commit: 9cacac2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📊 Tachometer Benchmark ResultsSummarynop-update
render
update
update-reflect
Resultslit-element-list
render
update
update-reflect
lit-html-kitchen-sink
render
update
nop-update
lit-html-repeat
render
update
lit-html-template-heavy
render
update
reactive-element-list
render
update
update-reflect
|
| "lint-staged": "^13.0.3", | ||
| "mocha": "^10.0.0", | ||
| "prettier": "^2.4.1", | ||
| "prettier": "^2.7.1", |
There was a problem hiding this comment.
Is this needed in this PR? Does it change formatting and if so was that applied to all packages?
There was a problem hiding this comment.
I tried updating it because the formatter was just breaking a certain code construct by inserting a random semicolon. I couldn't reproduce it in the prettier REPL, and ended up just changing the code.
We apparently don't include format in CI anymore, because (1) there were a couple of files that weren't formatted, and (2) there were a couple of generated files that were errantly not being excluded from lint (npm run format runs lint first, for some reason). Outside of those changes, I did run format and it doesn't change anything.
| ): ClassDeclaration => { | ||
| return new ClassDeclaration({ | ||
| name: declaration.name?.text, | ||
| name: declaration.name?.text ?? '', |
There was a problem hiding this comment.
I think I like name being undefined if a class actually doesn't have a name. What was this change for?
There was a problem hiding this comment.
This change makes all Declarations now extend a common base class that has name: string (before some were string | undefined). Ultimately I think this is correct since I don't think we need any anonymous declarations in the model -- if an anonymous class/function expression is assigned to a const, we'll use that name in the declaration (I have later versions that do that). Once we support that, this will go away, so I'll add a TODO.
There was a problem hiding this comment.
We could have something like:
customElements.define('my-element, class extends LitElement { ... });Rare, but possible.
| import {IPackageJson as PackageJson} from 'package-json-type'; | ||
| export {PackageJson}; | ||
|
|
||
| export type ModuleWithDeclarations<T extends Declaration> = { |
There was a problem hiding this comment.
Module already has declarations. Can you add a comment on what this is for? To narrow the declaration type?
There was a problem hiding this comment.
Yeah, this is the return value from getModulesWithDeclarations, which returns a filtered list of modules containing a certain declaration type AND the filtered list of those declarations (in order to implement getLitElementModules()). This was probably premature factoring, I'll just revert this to getLitElementModules(); I can't really think of a use case for getting modules filtered by a different declaration type.
| this.modules = init.modules; | ||
| } | ||
|
|
||
| getModulesWithDeclarations<T extends Declaration>( |
There was a problem hiding this comment.
Removed, and commented getLitElementModules
| constructor(init: DeclarationInit) { | ||
| this.name = init.name; | ||
| } | ||
| isVariableDeclaration(): this is VariableDeclaration { |
There was a problem hiding this comment.
If we followed the module object pattern like TypeScript, we could also have a bunch of top-level functions for model object, like analyzer.isClassDeclaration(), etc.
|
|
||
| // Any non-type exports below must be safe to use on objects between multiple | ||
| // versions of the analyzer library | ||
| export {getImportsStringForReferences} from './lib/model.js'; |
There was a problem hiding this comment.
As a follow on, let's consider putting this on the analyzer itself and passing that around. That way we don't have to be careful about this.
sorvell
left a comment
There was a problem hiding this comment.
LGTM, just one comment to handle as a follow on.
| ): ClassDeclaration => { | ||
| return new ClassDeclaration({ | ||
| name: declaration.name?.text, | ||
| name: declaration.name?.text ?? '', |
There was a problem hiding this comment.
We could have something like:
customElements.define('my-element, class extends LitElement { ... });Rare, but possible.
Fixes #3234 by ensuring that consumers of an analyzer model don't use incompatible helper methods (due to instanceof, caching, etc.) from a separate installation of the analyzer library.
Restricts package exports to
index.js, and only exports the Analyzer class + types (and select cross-package-safe helpers). Helpers likeisLitElementDeclarationandgetModulesWithDeclarationsare now class methods on model classes, rather than standalone module exports.