-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generated type declarations #189
Conversation
@@ -1,69 +1,239 @@ | |||
export class XElement extends HTMLElement { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here’s a good example — this should have said export default class XElement extends HTMLElement {
(see the default
). Easy to miss since we often don’t depend on this module. Generating it from well-considered JSDoc “types” feels like a better way to ensure this stays accurate.
static template(html: Function, engine: { | ||
[key: string]: Function; | ||
}): (properties: object, host: HTMLElement) => any; | ||
static "__#1@#analyzeConstructor"(constructor: any): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… This, is annoying. TypeScript does want to track private fields for [reasons], so as far as I can tell, you cannot remove this stuff.
@@ -3,11 +3,12 @@ | |||
"description": "A dead simple starting point for custom elements.", | |||
"version": "1.0.0", | |||
"license": "Apache-2.0", | |||
"repository": "https://github.com/Netflix/x-element", | |||
"repository": "github:Netflix/x-element", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through some of the npm documentation again and tried to further “modernize” this package.json
— worth further scrutiny for sure though.
package.json
Outdated
@@ -17,19 +18,23 @@ | |||
"lint": "eslint --max-warnings=0 .", | |||
"lint-fix": "eslint --fix .", | |||
"test": "node test.js | tap-parser -l", | |||
"build": "tsc", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still need to figure out how we want to include this output…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@theengineear Do you need to? If you're using JSDoc, TypeScript will import the file as typed.
Nevermind, I thought that worked but I can't get it to work consistently locally. Any reason it couldn't be stored right next to the output file in the NPM package/published directory, and stored that way? That's how most libs do it, as far as I've seen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the entire interface is really a single class — I do think it makes sense to keep this checked into source as a sibling of the file itself. It allows us to scrutinize any changes that could happen there.
That said… that’s just my current opinion there. It’s completely subject to change if it ends up being overly cumbersome!
tsconfig.tsbuildinfo
Outdated
@@ -0,0 +1 @@ | |||
{"root":["./x-element.js"],"version":"5.6.3"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what this is all about. Can we .gitignore
this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@theengineear You could merge the contents into the tsconfig.json. This file is helpful for splitting the project into multiple project references. However, TypeScript also just allows you to define these references in the tsconfig.json
if you need them anyway. It just supports allowing you using a separate config file, for which this file name is the default. I don't know why someone would choose to maintain a separate file from ts-config-- that probably makes more sense from the perspective of very large projects.
Anyway, since x-element is intended to be a single file import, I don't imagine you'll need this unless you're planning to add accessory projects to the repo. I'd just delete it for now. The version property doesn't appear to be an officially supported property for tsconfig, and you're already using the files
attribute instead of root
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the detailed response! I expected to be the one answering my own question there 😅
I’ll ignore the file 👌 Scratch that — Looks like I created it earlier when I must have been playing around with some configuration. Just deleted it 🤘
Another step I’d like to take is publishing this branch to JSR as throw-away exercise. I’d be curious to see if it significantly improves the experience there. |
x-element.js
Outdated
@@ -899,110 +975,122 @@ export default class XElement extends HTMLElement { | |||
static #prototypeInterface = new Set(Object.getOwnPropertyNames(XElement.prototype)); | |||
} | |||
|
|||
/** Wrapper to document public interface to the default templating engine. */ | |||
class TemplateEngine { | |||
// TODO: If / when we remove `repeat` in favor of `map` — we can probably delete |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What needs to happen in order for us to remove repeat
? It seems like we'd love to do it, but I'm guessing there's a good bit of legacy code. Is there any reason we can't, say, change the version number to 2.0.0 to indicate a breaking change and incentivize people to upgrade by letting them know that type checking is now available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only thing we really need to do is have the next release be a 2.x
release so that we’re following semantic versioning. It’s not much of a hassle to drag along repeat
until we’re actually ready to make that change though 👌
This way, we can continue shipping incremental changes in 1.x
without having to manage multiple, major versions or anything.
b69eb1f
to
f9d3bad
Compare
@@ -12,6 +12,8 @@ jobs: | |||
registry-url: 'https://registry.npmjs.org' | |||
- run: npm ci | |||
- run: npm run lint | |||
- run: npm run type | |||
- run: git diff --exit-code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than add a “build” step. We now have a CI step that will fail if a diff is generated from running npm run type
. This is closer to the flow I think we want. I.e., rather than need to run a build to use the types… assert that the types were properly generated before allowing the merge.
// generated-js back to ts… it also seems to be the case that it will help | ||
// IDEs get to the right _js_ when using types. See | ||
// https://www.typescriptlang.org/docs/handbook/declaration-files/dts-from-js.html | ||
"declarationMap": true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After re-reviewing this. I think it’s actually most correct to emit a source map.
- If you’re using the JS on it’s own — the source map is inert (since our JS is running as-is).
- If you’re using the TS declaration file, the source map will hint IDEs to route you back to the original JS.
This was tricky to wrap my head around at first since I typically think about these source mappings as a way to go from the generated JS back to the original TS — but, it seems like you can leverage them to hint IDEs to do the opposite as well.
"/demo", | ||
"/test", | ||
"/etc" | ||
], | ||
"devDependencies": { | ||
"@netflix/eslint-config": "^3.0.0", | ||
"eslint-plugin-jsdoc": "^50.3.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After using this for a little while — I feel like this is a pretty good solution. Open to other suggestions though. FWIW, I tried using TypeScript to generate errors here and I kept feeling like it wasn’t doing what I wanted it to do — could be that I had it set up wrong though!
f9d3bad
to
71fa53b
Compare
*/ | ||
/** | ||
* A property value. | ||
* @typedef {object} Property |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ll be curious to see how tools like JSR auto-doc this stuff!
71fa53b
to
5fc6d6e
Compare
5fc6d6e
to
79f945c
Compare
79f945c
to
4018e8d
Compare
* } | ||
* }; | ||
* } | ||
* ```js |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSDoc also has an @example
tag… but this feels more natural to write code blocks like this and it appears to be supported by JSR.
"bump": "./bump.sh" | ||
}, | ||
"files": [ | ||
"/x-element.js", | ||
"/x-element.d.ts", | ||
"/x-element.d.ts.map", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to generate a source map?
@@ -1,5 +1,12 @@ | |||
{ | |||
"name": "@netflix/x-element", | |||
"version": "1.0.0", | |||
"exports": "./x-element.js" | |||
"exports": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems wrong to not explicitly export the src
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSR’s documentation is not great here. I’ve added back the other files, which causes JSR to flag us as “slow” and throw warnings. I think that’s ok for now though.
I’m going to follow along on jsr-io/jsr#494 — hopefully things will get better once our JSDoc-style path forward here is accepted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awesome!
FYI, I think JSR is gonna wrongly flag this package as “slow” until jsr-io/jsr#494 is resolved. I think this should all work eventually though 👌 |
4018e8d
to
7605866
Compare
Previously, the “x-element.d.ts” file was hand-curated, which was prone to falling out of date. Because the TypeScript team manages JSDoc, it’s fairly straightforward to properly “type” your JS with JSDoc and output declarations which can be used by folks writing TypeScript — all of that without needing to actually author TypeScript ourselves.† Additionally, tools like JSR will build basic documentation for libraries which author JSDoc comments, so some wins there. Finally, to ensure best practices for our JSDocs, we enable some recommended rules from the eslint plugin. † One goal of “x-element” is to be _highly_ portable, it’s why no dependencies exist and why the “x-element.js” file can be used _verbatim_ without a build step.
7605866
to
54c9d2b
Compare
Going to get this merged in — I’ll play around with some |
Generate “x-element.d.ts” from JSDoc comments.
Previously, the “x-element.d.ts” file was hand-curated, which was prone
to falling out of date.
Because the TypeScript team manages JSDoc, it’s fairly straightforward
to properly “type” your JS with JSDoc and output declarations which can
be used by folks writing TypeScript — all of that without needing to
actually author TypeScript ourselves.†
Additionally, tools like JSR will build basic documentation for
libraries which author JSDoc comments, so some wins there.
Finally, to ensure best practices for our JSDocs, we enable some
recommended rules from the eslint plugin.
† One goal of “x-element” is to be highly portable, it’s why no
dependencies exist and why the “x-element.js” file can be used
verbatim without a build step.