Replies: 4 comments 21 replies
-
A friend did point out that this would be less efficient. If we do stick with the adapter pattern, I'm happy with that but we really need to figure the strong typing out. It is currently broken |
Beta Was this translation helpful? Give feedback.
-
I don’t really understand what would be impossible in TypeScript? I’m assuming that removing adapters will cut down on bundle size and likely will improve performance as well: just building an object model instead of calling functions for everything should be faster (although this needs to be verified). |
Beta Was this translation helpful? Give feedback.
-
My current thoughts — let me know if this makes sense. Afaict what we are looking for is opaque default types for the type map. TS doesn't support that, but one way to simulate opaque types is to make the default types unique objects. export interface TreeAdapterTypeMap<
Document = { type?: 'Document' },
DocumentFragment = { type?: 'DocumentFragment' },
Element = { type?: 'Element' },
CommentNode = { type?: 'CommentNode' },
TextNode = { type?: 'TextNode' },
Template = { type?: 'Template' },
DocumentType = { type?: 'DocumentType' },
ParentNode = Document | DocumentFragment | Element | Template,
ChildNode = Element | Template | CommentNode | TextNode | DocumentType,
Node = ParentNode | ChildNode
> {
document: Document;
documentFragment: DocumentFragment;
element: Element;
commentNode: CommentNode;
textNode: TextNode;
template: Template;
documentType: DocumentType;
parentNode: ParentNode;
childNode: ChildNode;
node: Node;
} This seems to do the job in terms of getting good types throughout the codebase. Of course, there is a lot to fix up afterwards, but that's a separate issue. |
Beta Was this translation helpful? Give feedback.
-
I have opened #42 with how I think the types should work. Mostly what I posted before, with some fixes. I am struggling to find a way to sneak bad code through this anymore — @43081j please let me know if you can think of anything. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Currently, tree adapters exist as a concept so we can instruct the parser on how to build up an AST, any AST.
This allows us to have parse5 produce its own AST or a htmlparser2 AST for example.
Sounds like an outcome we may want, but im feeling more and more like its definitely the wrong solution to the problem.
It isn't possible to strongly type it
Our current types, and the ones in DT (which i wrote) are wrong.
All along, we thought this pattern worked:
but it doesn't. all the types narrow to
unknown
, the compiler will allow you togetAttribute(commentNode, 'foo')
becauseT['comment']
andT['element']
both ultimately resolve tounknown
.This isn't fixable.
Type maps won't work, tuples of types won't work.
I talked to a few people on typescript discord and we came up with this:
but this doesn't work either. because
TNode
can't be defined. where/how can we define it? it can't be a type parameter, because then it could be anything (yet again) which meansTElement
may not necessarily be assignable to it, so tsc will fail.we would have to repeat ourselves with the full union every time we reference
TNode
, and no longer have aTNode
. craziness.It increases complexity, bugs, etc
JS parsers generally implement an esprima-compatible AST, because having a bunch of unrelated, incompatible ASTs would be a terrible idea. They did the right thing.
By not having one standard AST like this, we have a crazy amount of over-genericised complexity trying to handle the fact that everything can be anything. This means we definitely have more bugs, more complexity and lower performance than if we had a well known data structure.
Consumers need to read docs in at least two places
A consumer needs to read the docs for the parser and the tree adapter to find out what will happen.
Solution
We should remove tree adapters entirely, making parse5 produce a single, standard AST.
We can then introduce the concept of an 'output transform' which can consume the parse5 AST and output something else.
This would lead to types like so:
meaning we don't care anymore about all this over-generic nonsense until the very end, and even then its just a simple mapper function.
cc @fb55
Beta Was this translation helpful? Give feedback.
All reactions