Skip to content

Commit be83628

Browse files
authored
improve parser (#9)
* improve parser * update
1 parent fed381c commit be83628

17 files changed

+18395
-20
lines changed

play-astro/.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ module.exports = {
1717
rules: {
1818
"prettier/prettier": "off",
1919
"react/jsx-equals-spacing": "error",
20+
21+
// Incompatible rules
22+
"react/no-unknown-property": "off",
2023
},
2124
},
2225
],
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
overrides: [
3+
{
4+
files: ["*.astro"],
5+
rules: {
6+
"prettier/prettier": "error",
7+
},
8+
},
9+
],
10+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
import { format } from "date-fns"
3+
4+
// Welcome to Astro!
5+
// Write JavaScript & TypeScript here, in the "component script."
6+
// This will run during the build, but never in the final output.
7+
// Use these variables in the HTML template below.
8+
//
9+
// Full Syntax:
10+
// https://docs.astro.build/core-concepts/astro-components/
11+
12+
const builtAt: Date = new Date()
13+
const builtAtFormatted = format(builtAt, "MMMM dd, yyyy -- H:mm:ss.SSS")
14+
---
15+
16+
<html lang="en">
17+
<head>
18+
<meta charset="UTF-8" />
19+
<title>Astro Playground</title>
20+
<style>
21+
header {
22+
display: flex;
23+
flex-direction: column;
24+
align-items: center;
25+
text-align: center;
26+
margin-top: 15vh;
27+
font-family: Arial;
28+
}
29+
.note {
30+
margin: 0;
31+
padding: 1rem;
32+
border-radius: 8px;
33+
background: #e4e5e6;
34+
border: 1px solid #bbb;
35+
}
36+
</style>
37+
</head>
38+
<body>
39+
<header>
40+
<img
41+
width="60"
42+
height="80"
43+
src="https://bestofjs.org/logos/astro.svg"
44+
alt="Astro logo"
45+
/>
46+
<h1>Hello, Astro!</h1>
47+
<p class="note">
48+
<strong>RENDERED AT:</strong><br />
49+
{builtAtFormatted}
50+
</p>
51+
</header>
52+
</body>
53+
</html>

src/astro/index.ts

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
AttributeNode,
33
CommentNode,
4+
DoctypeNode,
45
Node,
56
ParentNode,
67
TagLikeNode,
@@ -28,36 +29,26 @@ export function isParent(node: Node): node is ParentNode {
2829
/** walk element nodes */
2930
export function walkElements(
3031
parent: ParentNode,
32+
code: string,
3133
cb: (n: Node, parent: ParentNode) => void,
3234
): void {
33-
let children = parent.children
34-
if (parent.type === "root" && children.every((n) => n.position)) {
35-
// The order of comments and frontmatter may be changed.
36-
children = [...children].sort(
37-
(a, b) => a.position!.start.offset - b.position!.start.offset,
38-
)
39-
}
35+
const children = getSortedChildren(parent, code)
4036
for (const node of children) {
4137
cb(node, parent)
4238
if (isParent(node)) {
43-
walkElements(node, cb)
39+
walkElements(node, code, cb)
4440
}
4541
}
4642
}
4743

4844
/** walk nodes */
4945
export function walk(
5046
parent: ParentNode,
47+
code: string,
5148
enter: (n: Node | AttributeNode, parent: ParentNode) => void,
5249
leave?: (n: Node | AttributeNode, parent: ParentNode) => void,
5350
): void {
54-
let children = parent.children
55-
if (parent.type === "root" && children.every((n) => n.position)) {
56-
// The order of comments and frontmatter may be changed.
57-
children = [...children].sort(
58-
(a, b) => a.position!.start.offset - b.position!.start.offset,
59-
)
60-
}
51+
const children = getSortedChildren(parent, code)
6152
for (const node of children) {
6253
enter(node, parent)
6354
if (isTag(node)) {
@@ -67,7 +58,7 @@ export function walk(
6758
}
6859
}
6960
if (isParent(node)) {
70-
walk(node, enter, leave)
61+
walk(node, code, enter, leave)
7162
}
7263
leave?.(node, parent)
7364
}
@@ -261,3 +252,45 @@ export function skipSpaces(string: string, position: number): number {
261252
}
262253
return position
263254
}
255+
256+
/**
257+
* Get children
258+
*/
259+
function getSortedChildren(parent: ParentNode, code: string) {
260+
if (parent.type === "root" && parent.children[0]?.type === "frontmatter") {
261+
// The order of comments and frontmatter may be changed.
262+
const children = [...parent.children]
263+
if (children.every((n) => n.position)) {
264+
return children.sort(
265+
(a, b) => a.position!.start.offset - b.position!.start.offset,
266+
)
267+
}
268+
let start = skipSpaces(code, 0)
269+
if (code.startsWith("<!", start)) {
270+
const frontmatter = children.shift()!
271+
const before: (CommentNode | DoctypeNode)[] = []
272+
let first
273+
while ((first = children.shift())) {
274+
start = skipSpaces(code, start)
275+
if (
276+
first.type === "comment" &&
277+
code.startsWith("<!--", start)
278+
) {
279+
start = code.indexOf("-->", start + 4) + 3
280+
before.push(first)
281+
} else if (
282+
first.type === "doctype" &&
283+
code.startsWith("<!", start)
284+
) {
285+
start = code.indexOf(">", start + 2) + 1
286+
before.push(first)
287+
} else {
288+
children.unshift(first)
289+
break
290+
}
291+
}
292+
return [...before, frontmatter, ...children]
293+
}
294+
}
295+
return parent.children
296+
}

src/parser/astro-parser/parse.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ function fixLocations(node: ParentNode, code: string): void {
3030
let start = 0
3131
walk(
3232
node,
33+
code,
3334
(node) => {
3435
if (node.type === "frontmatter") {
3536
start = node.position!.start.offset = tokenIndex(
@@ -82,6 +83,9 @@ function fixLocations(node: ParentNode, code: string): void {
8283
if (!node.position) {
8384
node.position = { start: {}, end: {} } as any
8485
}
86+
if (!node.position!.end) {
87+
node.position!.end = {} as any
88+
}
8589
start = node.position!.start.offset = tokenIndex(
8690
code,
8791
"<!",

src/parser/process-template.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function processTemplate(
3838
}
3939

4040
// eslint-disable-next-line complexity -- X(
41-
walkElements(resultTemplate.ast, (node, parent) => {
41+
walkElements(resultTemplate.ast, ctx.code, (node, parent) => {
4242
if (node.type === "frontmatter") {
4343
const start = node.position!.start.offset
4444
script.appendOriginal(start)

0 commit comments

Comments
 (0)