Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/open-tag-comments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"htmljs-parser": minor
---

Add an `onOpenTagComment` handler for a JavaScript comment that stands alone in an open tag, eg `<div /* c */ class="box">` or a `// why` line between attributes, which the parser used to consume without an event. A comment that follows a value is still part of that value. It is a separate handler from `onComment`, so a consumer only sees these comments once it handles them.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,19 @@ const parser = createParser({
range.value; // Another range that includes only the value itself without the leading ...
},

/**
* Called after parsing a JavaScript comment that stands alone in an open tag.
* A comment that follows a value is part of that value instead.
*
* @example
* 1╭─ <div /* hi */ class="x">
* │ │ ╰─ openTagComment.value " hi "
* ╰─ ╰─ openTagComment "/* hi */"
*/
onOpenTagComment(range) {
range.value; // Another range that only includes the contents of the comment.
},

/**
* Called once we've completed parsing the open tag.
*
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
1╭─ div /* c */ a=1
│ │ ││╰─ attrValue.value
│ │ │╰─ attrValue "=1"
│ │ ╰─ attrName
│ │ │ │ ││╰─ attrValue.value
│ │ │ │ │╰─ attrValue "=1"
│ │ │ │ ╰─ attrName
│ │ │ ╰─ openTagComment.value " c "
│ │ ╰─ openTagComment "/* c */"
╰─ ╰─ tagName "div"
2╭─ span // d
│ │ │ ╰─ openTagComment.value " d"
│ │ ╰─ openTagComment "// d"
│ ├─ closeTagEnd(div)
│ ├─ openTagEnd
╰─ ╰─ tagName "span"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
1╭─ <div /* after the name */ class="box">x</div>
│ ││ │ │ │ ││ │││ │ ╰─ closeTagEnd(div)
│ ││ │ │ │ ││ │││ ╰─ closeTagName "div"
│ ││ │ │ │ ││ ││╰─ closeTagStart "</"
│ ││ │ │ │ ││ │╰─ text
│ ││ │ │ │ ││ ╰─ openTagEnd
│ ││ │ │ │ │╰─ attrValue.value "\"box\""
│ ││ │ │ │ ╰─ attrValue "=\"box\""
│ ││ │ │ ╰─ attrName "class"
│ ││ │ ╰─ openTagComment.value " after the name "
│ ││ ╰─ openTagComment "/* after the name */"
│ │╰─ tagName "div"
╰─ ╰─ openTagStart
2╭─ <div
│ │╰─ tagName "div"
╰─ ╰─ openTagStart
3╭─ // why the attrs
│ │ ╰─ openTagComment.value " why the attrs"
╰─ ╰─ openTagComment "// why the attrs"
4╭─ class="box"/>
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
│ │ │╰─ attrValue.value "\"box\""
│ │ ╰─ attrValue "=\"box\""
╰─ ╰─ attrName "class"
5╭─ <input hidden // after a name-only attr
│ ││ │ │ ╰─ openTagComment.value " after a name-only attr"
│ ││ │ ╰─ openTagComment "// after a name-only attr"
│ ││ ╰─ attrName "hidden"
│ │╰─ tagName "input"
╰─ ╰─ openTagStart
6╭─ type="text">
│ │ ││ ╰─ openTagEnd
│ │ │╰─ attrValue.value "\"text\""
│ │ ╰─ attrValue "=\"text\""
╰─ ╰─ attrName "type"
7╭─ <a href="/" // follows a value, so part of it
│ ││ │ │╰─ attrValue.value "\"/\" // follows a value, so part of it"
│ ││ │ ╰─ attrValue "=\"/\" // follows a value, so part of it"
│ ││ ╰─ attrName "href"
│ │╰─ tagName
╰─ ╰─ openTagStart
8╭─ title="home"/>
│ │ ││ ╰─ openTagEnd:selfClosed "/>"
│ │ │╰─ attrValue.value "\"home\""
│ │ ╰─ attrValue "=\"home\""
╰─ ╰─ attrName "title"
9╰─
8 changes: 8 additions & 0 deletions src/__tests__/fixtures/open-tag-comments/input.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div /* after the name */ class="box">x</div>
<div
// why the attrs
class="box"/>
<input hidden // after a name-only attr
type="text">
<a href="/" // follows a value, so part of it
title="home"/>
3 changes: 3 additions & 0 deletions src/__tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ for (const entry of fs.readdirSync(FIXTURES)) {
onComment(range) {
addValueRange("comment", range);
},
onOpenTagComment(range) {
addValueRange("openTagComment", range);
},
onOpenTagStart(range) {
addRange("openTagStart", range);
},
Expand Down
18 changes: 2 additions & 16 deletions src/states/CONCISE_HTML_CONTENT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,24 +160,10 @@ export const CONCISE_HTML_CONTENT: StateDefinition = {

switch (child.state) {
case STATE.JS_COMMENT_LINE:
this.options.onComment?.({
start: child.start,
end: child.end,
value: {
start: child.start + 2, // strip //
end: child.end,
},
});
this.options.onComment?.(STATE.getJSCommentRange(child));
break;
case STATE.JS_COMMENT_BLOCK: {
this.options.onComment?.({
start: child.start,
end: child.end,
value: {
start: child.start + 2, // strip /*
end: child.end - 2, // strip */,
},
});
this.options.onComment?.(STATE.getJSCommentRange(child));

if (!this.consumeWhitespaceOnLine(0)) {
// Make sure there is only whitespace on the line
Expand Down
18 changes: 2 additions & 16 deletions src/states/HTML_CONTENT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,24 +178,10 @@ export const HTML_CONTENT: StateDefinition<HTMLContentMeta> = {
return(child) {
switch (child.state) {
case STATE.JS_COMMENT_LINE:
this.options.onComment?.({
start: child.start,
end: child.end,
value: {
start: child.start + 2, // strip //
end: child.end,
},
});
this.options.onComment?.(STATE.getJSCommentRange(child));
break;
case STATE.JS_COMMENT_BLOCK: {
this.options.onComment?.({
start: child.start,
end: child.end,
value: {
start: child.start + 2, // strip /*
end: child.end - 2, // strip */,
},
});
this.options.onComment?.(STATE.getJSCommentRange(child));
break;
}
}
Expand Down
25 changes: 24 additions & 1 deletion src/states/JS_COMMENT_LINE.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { STATE, type StateDefinition } from "../internal.ts";
import {
type Meta,
type Ranges,
STATE,
type StateDefinition,
} from "../internal.ts";
import * as CODE from "../util/codes.ts";
import * as TagType from "../util/tag-type.ts";

Expand Down Expand Up @@ -47,3 +52,21 @@ export const JS_COMMENT_LINE: StateDefinition = {
/* node:coverage ignore next */ // never has child states
return() {},
};

/**
* The range of a JavaScript line or block comment that a state returned from,
* with the delimiters stripped from its value.
*/
export function getJSCommentRange(comment: Meta): Ranges.Value {
return {
start: comment.start,
end: comment.end,
value: {
start: comment.start + 2, // strip // or /*
end:
comment.state === STATE.JS_COMMENT_BLOCK
? comment.end - 2 // strip */
: comment.end,
},
};
}
13 changes: 12 additions & 1 deletion src/states/OPEN_TAG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,18 @@ export const OPEN_TAG: StateDefinition<OpenTagMeta> = {
},

return(child, tag) {
if (child.state !== STATE.EXPRESSION) return;
switch (child.state) {
case STATE.JS_COMMENT_LINE:
case STATE.JS_COMMENT_BLOCK:
// A separate event, since a consumer that adds every `onComment` to
// the current body would otherwise put these in the tag's body.
this.options.onOpenTagComment?.(STATE.getJSCommentRange(child));
return;
case STATE.EXPRESSION:
break;
default:
return;
}

switch (tag.stage) {
case TAG_STAGE.VAR: {
Expand Down
1 change: 1 addition & 0 deletions src/util/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export interface ParserOptions {
onAttrValue?(data: Ranges.AttrValue): void;
onAttrMethod?(data: Ranges.AttrMethod): void;
onAttrSpread?(data: Ranges.Value): void;
onOpenTagComment?(data: Ranges.Value): void;
onOpenTagEnd?(data: Ranges.OpenTagEnd): void;
onCloseTagStart?(data: Range): void;
onCloseTagName?(data: Range): void;
Expand Down
Loading