Skip to content

Commit

Permalink
implement
Browse files Browse the repository at this point in the history
  • Loading branch information
yeonjuan committed Nov 17, 2024
1 parent 586186b commit f41b47e
Show file tree
Hide file tree
Showing 8 changed files with 631 additions and 11 deletions.
2 changes: 1 addition & 1 deletion packages/parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"url": "https://github.com/yeonjuan/html-eslint/issues"
},
"dependencies": {
"es-html-parser": "^0.0.9"
"es-html-parser": "^0.0.10"
},
"devDependencies": {
"typescript": "^4.9.4"
Expand Down
59 changes: 58 additions & 1 deletion packages/template-parser/lib/template-parser.js
Original file line number Diff line number Diff line change
@@ -1 +1,58 @@
module.exports = class TemplateParser {};
const esHtmlParser = require("es-html-parser");
const { traverse } = require("./traverser");
/**
* @typedef {import("estree").TemplateLiteral} TemplateLiteral
* @typedef {import("./types").TemplateHTMLVisitor} TemplateHTMLVisitor
*/

/**
*
* @param {TemplateLiteral} node
* @param {TemplateHTMLVisitor} visitors
*/
function parse(node, visitors) {
/**
* @type {string[]}
*/
const htmlParts = [];
const quasis = node.quasis;
const rangeOffset = node.range[0] + 1;
const lineOffset = node.loc.start.line - 1;

quasis.forEach((element) => {
htmlParts.push(element.value.raw);
});

const html = htmlParts.join("");

const { ast } = esHtmlParser.parse(html, {
tokenAdapter: {
finalizeLocation(token) {
const startLine = token.loc.start.line + lineOffset;
const columnOffset =
startLine === node.loc.start.line ? node.loc.end.column + 1 : 0;

return {
start: {
line: startLine,
column: token.loc.start.column + columnOffset,
},
end: {
line: token.loc.end.line + lineOffset,
column: token.loc.end.column + columnOffset,
},
};
},
finalizeRange(token) {
return [token.range[0] + rangeOffset, token.range[1] + rangeOffset];
},
},
});

traverse(ast, visitors);
return ast;
}

module.exports = {
parse,
};
79 changes: 79 additions & 0 deletions packages/template-parser/lib/traverser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* @typedef {import("es-html-parser").AnyNode} AnyNode
* @typedef {import("./types").TemplateHTMLVisitor} TemplateHTMLVisitor
*/

const { NodeTypes } = require("es-html-parser");

const visitorKeys = {
[NodeTypes.Document]: ["children"],
[NodeTypes.Attribute]: ["key", "startWrapper", "endWrapper", "value"],
[NodeTypes.AttributeKey]: [],
[NodeTypes.AttributeValue]: [],
[NodeTypes.AttributeValueWrapperEnd]: [],
[NodeTypes.AttributeValueWrapperStart]: [],
[NodeTypes.CloseScriptTag]: [],
[NodeTypes.CloseStyleTag]: [],
[NodeTypes.CloseTag]: [],
[NodeTypes.Comment]: ["open", "close", "value"],
[NodeTypes.CommentContent]: [],
[NodeTypes.CommentOpen]: [],
[NodeTypes.CommentClose]: [],
[NodeTypes.Doctype]: ["open", "close", "attributes"],
[NodeTypes.DoctypeAttribute]: ["startWrapper", "value", "endWrapper"],
[NodeTypes.DoctypeAttributeValue]: [],
[NodeTypes.DoctypeAttributeWrapperEnd]: [],
[NodeTypes.DoctypeAttributeWrapperStart]: [],
[NodeTypes.DoctypeOpen]: [],
[NodeTypes.DoctypeClose]: [],
[NodeTypes.OpenScriptTagEnd]: [],
[NodeTypes.OpenScriptTagStart]: [],
[NodeTypes.OpenStyleTagEnd]: [],
[NodeTypes.OpenStyleTagStart]: [],
[NodeTypes.OpenTagEnd]: [],
[NodeTypes.OpenTagStart]: [],
[NodeTypes.ScriptTag]: [
"attributes",
"openStart",
"openEnd",
"close",
"value",
],
[NodeTypes.ScriptTagContent]: [],
[NodeTypes.StyleTag]: [
"attributes",
"openStart",
"openEnd",
"close",
"value",
],
[NodeTypes.StyleTagContent]: [],
[NodeTypes.Tag]: ["openStart", "openEnd", "close", "children", "attributes"],
[NodeTypes.Text]: [],
};

/**
*
* @param {AnyNode} node
* @param {TemplateHTMLVisitor} visitors
*/
function traverse(node, visitors) {
const visitor = visitors[node.type];
visitor && visitor(node);
const nextKeys = node[visitorKeys[node.type]];
if (!Array.isArray(nextKeys) || nextKeys.length === 0) {
return;
}
nextKeys.forEach((key) => {
const next = node[key];
if (Array.isArray(next)) {
next.forEach((n) => traverse(n, visitor));
} else {
traverse(next, visitor);
}
});
}

module.exports = {
traverse,
};
78 changes: 78 additions & 0 deletions packages/template-parser/lib/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type {
NodeTypes,
DocumentNode,
AttributeNode,
AttributeKeyNode,
AttributeValueNode,
AttributeValueWrapperEndNode,
AttributeValueWrapperStartNode,
CloseScriptTagNode,
CloseStyleTagNode,
CloseTagNode,
CommentContentNode,
CommentOpenNode,
CommentCloseNode,
DoctypeNode,
DoctypeAttributeNode,
DoctypeAttributeValueNode,
DoctypeAttributeWrapperEndNode,
DoctypeAttributeWrapperStartNode,
DoctypeOpenNode,
DoctypeCloseNode,
OpenScriptTagEndNode,
OpenScriptTagStartNode,
OpenStyleTagEndNode,
OpenStyleTagStartNode,
OpenTagEndNode,
OpenTagStartNode,
ScriptTagNode,
ScriptTagContentNode,
StyleTagNode,
StyleTagContentNode,
TagNode,
TextNode,
} from "es-html-parser";
import { Comment } from "estree";

export type TemplateHTMLVisitor = Partial<{
[NodeTypes.Document]: (node: DocumentNode) => void;
[NodeTypes.Attribute]: (node: AttributeNode) => void;
[NodeTypes.AttributeKey]: (node: AttributeKeyNode) => void;
[NodeTypes.AttributeValue]: (node: AttributeValueNode) => void;
[NodeTypes.AttributeValueWrapperEnd]: (
node: AttributeValueWrapperEndNode,
) => void;
[NodeTypes.AttributeValueWrapperStart]: (
node: AttributeValueWrapperStartNode,
) => void;
[NodeTypes.CloseScriptTag]: (node: CloseScriptTagNode) => void;
[NodeTypes.CloseStyleTag]: (node: CloseStyleTagNode) => void;
[NodeTypes.CloseTag]: (node: CloseTagNode) => void;
[NodeTypes.Comment]: (node: Comment) => void;
[NodeTypes.CommentContent]: (node: CommentContentNode) => void;
[NodeTypes.CommentOpen]: (node: CommentOpenNode) => void;
[NodeTypes.CommentClose]: (node: CommentCloseNode) => void;
[NodeTypes.Doctype]: (node: DoctypeNode) => void;
[NodeTypes.DoctypeAttribute]: (node: DoctypeAttributeNode) => void;
[NodeTypes.DoctypeAttributeValue]: (node: DoctypeAttributeValueNode) => void;
[NodeTypes.DoctypeAttributeWrapperEnd]: (
node: DoctypeAttributeWrapperEndNode,
) => void;
[NodeTypes.DoctypeAttributeWrapperStart]: (
node: DoctypeAttributeWrapperStartNode,
) => void;
[NodeTypes.DoctypeOpen]: (node: DoctypeOpenNode) => void;
[NodeTypes.DoctypeClose]: (node: DoctypeCloseNode) => void;
[NodeTypes.OpenScriptTagEnd]: (node: OpenScriptTagEndNode) => void;
[NodeTypes.OpenScriptTagStart]: (node: OpenScriptTagStartNode) => void;
[NodeTypes.OpenStyleTagEnd]: (node: OpenStyleTagEndNode) => void;
[NodeTypes.OpenStyleTagStart]: (node: OpenStyleTagStartNode) => void;
[NodeTypes.OpenTagEnd]: (node: OpenTagEndNode) => void;
[NodeTypes.OpenTagStart]: (node: OpenTagStartNode) => void;
[NodeTypes.ScriptTag]: (node: ScriptTagNode) => void;
[NodeTypes.ScriptTagContent]: (node: ScriptTagContentNode) => void;
[NodeTypes.StyleTag]: (node: StyleTagNode) => void;
[NodeTypes.StyleTagContent]: (node: StyleTagContentNode) => void;
[NodeTypes.Tag]: (node: TagNode) => void;
[NodeTypes.Text]: (node: TextNode) => void;
}>;
10 changes: 9 additions & 1 deletion packages/template-parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,20 @@
"scripts": {
"ts": "tsc",
"lint": "eslint . --ext .js",
"build": "tsc -p ./tsconfig.build.json"
"build": "tsc -p ./tsconfig.build.json",
"test": "jest --coverage"
},
"bugs": {
"url": "https://github.com/yeonjuan/html-eslint/issues"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"dependencies": {
"es-html-parser": "^0.0.10"
},
"devDependencies": {
"@types/estree": "^0.0.47",
"espree": "^10.3.0"
}
}
Loading

0 comments on commit f41b47e

Please sign in to comment.