Skip to content

Commit 83e3308

Browse files
DylanPierceyclaude
andcommitted
Let the parse hook only override tag body types and write trailing body comments
The built in node kinds (core statements, style blocks, attribute tags, void/text lists) are now decided before the getTagType hook is consulted, so consumers which always return a type get the same tree as the language server. Trailing comments in comment-only or attr-tag-only bodies are now written to the generated script, the parser returns the filename verbatim (normalization moved back to language-tools), and @marko/parse publishes as a minor while its API settles. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 47d9673 commit 83e3308

20 files changed

Lines changed: 510 additions & 177 deletions

File tree

.changeset/parse-package.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
"@marko/parse": major
2+
"@marko/parse": minor
33
---
44

5-
New package: the Marko CST parser previously embedded in `@marko/language-tools`, extracted so it can be shared by other tooling. Node types are strings, syntax errors and comments are exposed on the parse result, comments and static statements are part of `program.body`, and a `getTagType` option allows overriding how tag bodies parse.
5+
New package: the Marko CST parser previously embedded in `@marko/language-tools`, extracted so it can be shared by other tooling. Node types are strings, syntax errors and comments are exposed on the parse result, comments and static statements are part of `program.body`, the filename is returned verbatim, and a `getTagType` option allows overriding how tag bodies parse (the built in statement and attribute tag node kinds are decided first; the hook only overrides a tag's body type or forces a generic `Static` statement).

AGENTS.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
## Repo overview
44

5-
Monorepo for the Marko Language Server and related tooling. Four pnpm workspaces under `packages/`:
5+
Monorepo for the Marko Language Server and related tooling. Five pnpm workspaces under `packages/`:
66

77
| Package | Published as | Purpose |
88
| ----------------- | ------------------------------------------- | ----------------------------------------------------------- |
9-
| `language-tools` | `@marko/language-tools` | Core extraction/analysis of Marko files (leaf dependency) |
9+
| `parse` | `@marko/parse` | CST parser for Marko templates (leaf dependency) |
10+
| `language-tools` | `@marko/language-tools` | Core extraction/analysis of Marko files; depends on parse |
1011
| `language-server` | `@marko/language-server` | LSP implementation; depends on language-tools |
1112
| `type-check` | `@marko/type-check` | CLI type-checker (`mtc`); depends on language-tools |
1213
| `vscode` | `marko-vscode` (VS Code extension, private) | VS Code client; depends on language-server + language-tools |
@@ -18,8 +19,8 @@ TypeScript emits **only `.d.ts` files** (`emitDeclarationOnly: true`); esbuild (
1819
**Build order matters** due to project references:
1920

2021
```
21-
language-tools -> language-server -> vscode
22-
language-tools -> type-check
22+
parse -> language-tools -> language-server -> vscode
23+
parse -> language-tools -> type-check
2324
```
2425

2526
Commands:
@@ -33,7 +34,13 @@ The vscode build is the most complex: it bundles 4 entry points (including tests
3334

3435
**Build is always required before testing.** `pnpm test` at root runs `pnpm run build && pnpm -r --if-present run test`.
3536

36-
Only two packages have tests:
37+
Only three packages have tests:
38+
39+
### parse (mocha)
40+
41+
```sh
42+
pnpm --filter @marko/parse run test
43+
```
3744

3845
### language-server (mocha + mocha-snap)
3946

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div>
2+
3+
</div><div data-marko-node-id="2">
4+
5+
6+
</div><span data-marko-node-id="3">
7+
8+
</span><div data-marko-node-id="4">text</div>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## Diagnostics
2+
### Ln 2, Col 9
3+
```marko
4+
1 | <const/data = { a: 1 }/>
5+
> 2 | <loader|data|>
6+
| ^^^^ 'data' is declared but its value is never read.
7+
3 | // ^?
8+
4 | </loader>
9+
5 | <div>
10+
```
11+
12+
### Ln 2, Col 9
13+
```marko
14+
1 | <const/data = { a: 1 }/>
15+
> 2 | <loader|data|>
16+
| ^^^^ Parameter 'data' implicitly has an 'any' type.
17+
3 | // ^?
18+
4 | </loader>
19+
5 | <div>
20+
```
21+
22+
### Ln 6, Col 4
23+
```marko
24+
4 | </loader>
25+
5 | <div>
26+
> 6 | <@x/>
27+
| ^^ Object literal may only specify known properties, and '["x"]' does not exist in type 'Directives & Div'.
28+
7 | // ^?
29+
8 | </div>
30+
9 | <span>
31+
```
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
export interface Input {}
2+
(function (this: void) {
3+
const input = Marko._.any as Input;
4+
const $signal = Marko._.any as AbortSignal;
5+
const $global = Marko._.getGlobal(
6+
// @ts-expect-error We expect the compiler to error because we are checking if the MarkoRun.Context is defined.
7+
(Marko._.error, Marko._.any as MarkoRun.Context),
8+
);
9+
const data = Marko._.hoist(() => __marko_internal_hoist__data);
10+
const __marko_internal_tag_1 = Marko._.resolveTemplate(
11+
import("@marko/runtime-tags/tags/const.d.marko"),
12+
);
13+
{
14+
const data = Marko._.returned(() => __marko_internal_rendered_1);
15+
const __marko_internal_rendered_1 = Marko._.renderTemplate(
16+
__marko_internal_tag_1,
17+
)()()({
18+
value: { a: 1 },
19+
});
20+
const __marko_internal_tag_2 = Marko._.interpolated`loader`;
21+
Marko._.renderDynamicTag(__marko_internal_tag_2)()()({
22+
[Marko._.contentFor(__marko_internal_tag_2)]: (data) => {
23+
// ^?
24+
return Marko._.voidReturn;
25+
},
26+
});
27+
Marko._.renderNativeTag("div")()()({
28+
["x"]: {
29+
[Symbol.iterator]: Marko._.any,
30+
},
31+
// ^?
32+
});
33+
Marko._.renderNativeTag("span")()()({
34+
[Marko._.content]: (() => {
35+
// after
36+
return () => {
37+
return Marko._.voidReturn;
38+
};
39+
})(),
40+
});
41+
Marko._.renderNativeTag("div")()()({
42+
[Marko._.content]: (() => {
43+
// c
44+
return () => {
45+
return Marko._.voidReturn;
46+
};
47+
})(),
48+
});
49+
var __marko_internal_hoist__data = data;
50+
}
51+
Marko._.noop({ data, input, $global, $signal });
52+
return;
53+
})();
54+
const __marko_internal_api = "tags";
55+
export { __marko_internal_api as "~api" };
56+
export default new (class Template extends Marko._.Template<{
57+
render(
58+
input: Marko.TemplateInput<Input>,
59+
stream?: {
60+
write: (chunk: string) => void;
61+
end: (chunk?: string) => void;
62+
},
63+
): Marko.Out<never>;
64+
65+
render(
66+
input: Marko.TemplateInput<Input>,
67+
cb?: (err: Error | null, result: Marko.RenderResult<never>) => void,
68+
): Marko.Out<never>;
69+
70+
renderSync(input: Marko.TemplateInput<Input>): Marko.RenderResult<never>;
71+
72+
renderToString(input: Marko.TemplateInput<Input>): string;
73+
74+
stream(
75+
input: Marko.TemplateInput<Input>,
76+
): ReadableStream<string> & NodeJS.ReadableStream;
77+
78+
mount(
79+
input: Marko.TemplateInput<Input>,
80+
reference: Node,
81+
position?: "afterbegin" | "afterend" | "beforebegin" | "beforeend",
82+
): Marko.MountedTemplate<typeof input>;
83+
84+
api: typeof __marko_internal_api;
85+
_(): () => <__marko_internal_input extends unknown>(
86+
input: Marko.Directives &
87+
Input &
88+
Marko._.Relate<__marko_internal_input, Marko.Directives & Input>,
89+
) => Marko._.ReturnWithScope<__marko_internal_input, void>;
90+
}> {})();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<const/data = { a: 1 }/>
2+
<loader|data|>
3+
// ^?
4+
</loader>
5+
<div>
6+
<@x/>
7+
// ^?
8+
</div>
9+
<span>
10+
// after
11+
</span>
12+
div
13+
// c
14+
-- text

packages/language-server/src/__tests__/fixtures/script/comments/__snapshots__/comments.expected/index.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,27 @@ export { type Component };
1111
// @ts-expect-error We expect the compiler to error because we are checking if the MarkoRun.Context is defined.
1212
(Marko._.error, Marko._.any as MarkoRun.Context),
1313
);
14-
Marko._.noop({ component, state, out, input, $global, $signal });
14+
// Single-line comment */ // \n
15+
/*
16+
multi-line
17+
comment
18+
<!--
19+
20+
*/ /*
21+
HTML
22+
Comment
23+
*\/
24+
*\/ //
25+
\n
26+
*\/
27+
*/ Marko._.noop({
28+
component,
29+
state,
30+
out,
31+
input,
32+
$global,
33+
$signal,
34+
});
1535
return;
1636
})();
1737
const __marko_internal_api = "class";

packages/language-server/src/__tests__/fixtures/script/el-ref-hoist/__snapshots__/el-ref-hoist.expected/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ $el
2020
});
2121
{const $el = Marko._.el("div");
2222
Marko._.renderNativeTag("div")()()({
23+
// ^?
2324

2425
});
2526
const __marko_internal_tag_3 = (

packages/language-server/src/__tests__/fixtures/script/for-tag/__snapshots__/for-tag.expected/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export interface Input {}
6666
by: (item, index) => `${item}-${index}`,
6767
},
6868
() => {
69+
// ^? ^?
6970
return Marko._.voidReturn;
7071
},
7172
);
@@ -138,6 +139,7 @@ export interface Input {}
138139
by: (value, key) => `${value}-${key}`,
139140
},
140141
() => {
142+
// ^? ^?
141143
return Marko._.voidReturn;
142144
},
143145
);
@@ -191,6 +193,7 @@ export interface Input {}
191193
by: (index) => `${index}`,
192194
},
193195
() => {
196+
// ^?
194197
return Marko._.voidReturn;
195198
},
196199
);
@@ -266,6 +269,7 @@ export interface Input {}
266269
by: (index) => `${index}`,
267270
},
268271
() => {
272+
// ^?
269273
return Marko._.voidReturn;
270274
},
271275
);

packages/language-server/src/__tests__/fixtures/script/mutate-within-attr-tag/__snapshots__/mutate-within-attr-tag.expected/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface Input {}
3333
},
3434
[Symbol.iterator]: Marko._.any,
3535
},
36+
// ^?
3637
});
3738
var __marko_internal_hoist__count = count;
3839
}

0 commit comments

Comments
 (0)