-
Notifications
You must be signed in to change notification settings - Fork 83
Add parse function, emit AST
#274
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
Conversation
🦋 Changeset detectedLatest commit: ecdc90e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
jonathantneal
left a comment
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 can’t possibly fathom it all without a walk thru, but this looks phenomenal.
Co-authored-by: Jonathan Neal <jonathantneal@hotmail.com>
natemoo-re
left a comment
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.
Leaving some comments for reference
| doc.AppendChild(n) | ||
| } | ||
|
|
||
| result := printer.PrintToJSON(source, doc, parseOptions) |
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 very similar to the Transform function other than the way we print. Instead of generating a JS module from our AST, we have a new printer that generates stringified JSON.
| func (n ASTNode) String() string { | ||
| str := fmt.Sprintf(`{"type":"%s"`, n.Type) | ||
| if n.Kind != "" { | ||
| str += fmt.Sprintf(`,"kind":"%s"`, n.Kind) | ||
| } | ||
| if n.Name != "" { | ||
| str += fmt.Sprintf(`,"name":"%s"`, escapeForJSON(n.Name)) | ||
| } | ||
| if n.Value != "" || n.Type == "attribute" { | ||
| str += fmt.Sprintf(`,"value":"%s"`, escapeForJSON(n.Value)) | ||
| } | ||
| if len(n.Attributes) > 0 { | ||
| str += `,"attributes":[` | ||
| for i, attr := range n.Attributes { | ||
| str += attr.String() | ||
| if i < len(n.Attributes)-1 { | ||
| str += "," | ||
| } | ||
| } | ||
| str += `]` | ||
| } | ||
| if len(n.Directives) > 0 { | ||
| str += `,"directives":[` | ||
| for i, attr := range n.Directives { | ||
| str += attr.String() | ||
| if i < len(n.Directives)-1 { | ||
| str += "," | ||
| } | ||
| } | ||
| str += `]` | ||
| } | ||
| if len(n.Children) > 0 { | ||
| str += `,"children":[` | ||
| for i, node := range n.Children { | ||
| str += node.String() | ||
| if i < len(n.Children)-1 { | ||
| str += "," | ||
| } | ||
| } | ||
| str += `]` | ||
| } | ||
| if n.Position.Start.Line != 0 { | ||
| str += `,"position":{` | ||
| str += fmt.Sprintf(`"start":{"line":%d,"column":%d,"offset":%d}`, n.Position.Start.Line, n.Position.Start.Column, n.Position.Start.Offset) | ||
| if n.Position.End.Line != 0 { | ||
| str += fmt.Sprintf(`,"end":{"line":%d,"column":%d,"offset":%d}`, n.Position.End.Line, n.Position.End.Column, n.Position.End.Offset) | ||
| } | ||
| str += "}" | ||
| } | ||
| str += "}" | ||
| return str | ||
| } |
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.
Just want to note that our String() function is implemented manually, but recurses through the AST just fine.
I had originally used json.Marshal but it relies heavily on Reflection which is not well supported in tinygo. This is more performant, anyway.
| } | ||
| var node ASTNode | ||
|
|
||
| node.Position = positionAt(p, n, opts) |
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.
Position data is not super robust at the moment and might be wrong in some places. This should work but we'll need a cleanup pass to normalize this data in the parser.
| export interface BaseNode { | ||
| type: string; | ||
| position?: Position; | ||
| } | ||
|
|
||
| export interface ParentLikeNode extends BaseNode { | ||
| type: 'element' | 'component' | 'custom-element' | 'expression' | 'root'; | ||
| children: Node[]; | ||
| } | ||
|
|
||
| export interface LiteralNode extends BaseNode { | ||
| type: 'text' | 'doctype' | 'comment' | 'frontmatter'; | ||
| value: string; | ||
| } |
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.
| export interface AttributeNode extends BaseNode { | ||
| type: 'attribute'; | ||
| kind: 'quoted' | 'empty' | 'expression' | 'spread' | 'shorthand' | 'template-literal'; | ||
| name: string; | ||
| value: string; | ||
| } | ||
|
|
||
| export interface DirectiveNode extends Omit<AttributeNode, 'type'> { | ||
| type: 'directive'; | ||
| } |
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.
One choice worth calling out—I've split attributes and directives into two separate nodes. This should make it easy to find and validate official directive without needing to loop through all the existing attributes. The compiler filters them out for you.
matthewp
left a comment
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.
lgtm
* chore: enter pre * Treat all documents as fragments which generate no implicit tags (#264) * feat: remove "as", treat all documents as fragments with no implicit tags * test: fix failing tests * lint: remove unused utils * [DO NOT MERGE] add `renderHead` util to output (#265) * feat: add renderHead util to output * chore: update ci to run on `next` * test: update tests * chore: add changeset * fix transform output * Add `parse` function, emit AST (#274) * feat: implement Astro.self (#270) * feat: add parser * chore: lint * Update lib/compiler/README.md Co-authored-by: Jonathan Neal <jonathantneal@hotmail.com> Co-authored-by: Jonathan Neal <jonathantneal@hotmail.com> * chore: add changeset * test: update tests for no implicit tags * test: update tests for no implicit tags * chore: update tests for no implicit tags * chore: update build script * chore: update node bindings * chore: update wasm file * feat: expose AST types * chore: update tests for no implicit tags * [ci] release (next) (#288) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update exposed types * [ci] release (next) (#304) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Warn when using an expression on hoist `src` attr (#303) * Warn when using an expression on hoist `src` attr * Adds a changeset * Update the warning based on feedback * [ci] release (next) (#305) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: export `./types` * [ci] release (next) (#306) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: export all shared types * fix: export named types * [ci] release (next) (#307) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Client only metadata (#308) * Include metadata on client:only components * Adds a changeset * [ci] release (next) (#309) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Fix next `head` behavior (#310) * feat: update WASM tests * fix: prefer astro.Parse to astro.ParseFragment * fix: prefer `Parse` to `ParseFragment` * fix: update parse test * chore: add changeset * test: add parse-ii test * [ci] release (next) (#311) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Add `fragment` to AST (#312) * feat: add fragment node to AST output * fix: edge case with Fragment parsing in <head> * chore: add changeset * chore(lint): fix lint * chore(lint): fix lint * [ci] release (next) (#313) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Improve `renderHead` behavior (#315) * feat: improve render-head behavior * chore: add changeset * chore: fix wasm test * [ci] release (next) (#317) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Refactor WASM tests (#316) * refactor: switch tests to uvu * chore(ci): update test script * chore(lint): fix * test: enable head placeholder test * test: fix head placeholder test * refactor: remove escapeHTML usage, fix slot in head behavior * [ci] release (next) (#320) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: failing test * feat: expose fragment to AST (#314) Co-authored-by: Jonathan Neal <jonathantneal@hotmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Matthew Phillips <matthew@skypack.dev>
Changes
parsewhich can emit an AST@astrojs/compiler/utilswith awalkfunction andistype guards.Example
Testing
Docs
README has been updated. Docs should probably remain internal for a while until this is stabilized.