feat(html): add parse5/htmlparser2 printer (#2083)
parent
f399e90bc2
commit
d00956d51d
|
@ -98,6 +98,7 @@ function getParserOption() {
|
|||
value === "babylon" ||
|
||||
value === "typescript" ||
|
||||
value === "postcss" ||
|
||||
value === "parse5" ||
|
||||
value === "graphql"
|
||||
) {
|
||||
return value;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"jest-validate": "20.0.3",
|
||||
"minimist": "1.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"parse5": "3.0.2",
|
||||
"postcss": "^6.0.1",
|
||||
"postcss-less": "^1.0.0",
|
||||
"postcss-media-query-parser": "0.2.3",
|
||||
|
|
|
@ -31,6 +31,8 @@ function normalize(options) {
|
|||
|
||||
if (/\.(css|less|scss)$/.test(filepath)) {
|
||||
normalized.parser = "postcss";
|
||||
} else if (/\.html$/.test(filepath)) {
|
||||
normalized.parser = "parse5";
|
||||
} else if (/\.(ts|tsx)$/.test(filepath)) {
|
||||
normalized.parser = "typescript";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
// const createError = require("./parser-create-error");
|
||||
|
||||
function parse(text) {
|
||||
// Inline the require to avoid loading all the JS if we don't use it
|
||||
const parse5 = require("parse5");
|
||||
try {
|
||||
const ast = parse5.parse(text, {
|
||||
treeAdapter: parse5.treeAdapters.htmlparser2
|
||||
});
|
||||
return ast;
|
||||
} catch (error) {
|
||||
// throw createError(error.message, {
|
||||
// start: {
|
||||
// line: error.locations[0].line,
|
||||
// column: error.locations[0].column
|
||||
// }
|
||||
// } else {
|
||||
throw error;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = parse;
|
|
@ -1,22 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
function parse(text, opts) {
|
||||
let parseFunction;
|
||||
|
||||
if (opts.parser === "flow") {
|
||||
parseFunction = eval("require")("./parser-flow");
|
||||
} else if (opts.parser === "graphql") {
|
||||
parseFunction = eval("require")("./parser-graphql");
|
||||
} else if (opts.parser === "typescript") {
|
||||
parseFunction = eval("require")("./parser-typescript");
|
||||
} else if (opts.parser === "postcss") {
|
||||
parseFunction = eval("require")("./parser-postcss");
|
||||
} else {
|
||||
parseFunction = eval("require")("./parser-babylon");
|
||||
function getParseFunction(opts) {
|
||||
switch (opts.parser) {
|
||||
case "flow":
|
||||
return eval("require")("./parser-flow");
|
||||
case "graphql":
|
||||
return eval("require")("./parser-graphql");
|
||||
case "parse5":
|
||||
return eval("require")("./parser-parse5");
|
||||
case "postcss":
|
||||
return eval("require")("./parser-postcss");
|
||||
case "typescript":
|
||||
return eval("require")("./parser-typescript");
|
||||
default:
|
||||
return eval("require")("./parser-babylon");
|
||||
}
|
||||
}
|
||||
|
||||
function parse(text, opts) {
|
||||
try {
|
||||
return parseFunction(text);
|
||||
return getParseFunction(opts)(text);
|
||||
} catch (error) {
|
||||
const loc = error.loc;
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
"use strict";
|
||||
|
||||
const docBuilders = require("./doc-builders");
|
||||
const concat = docBuilders.concat;
|
||||
const join = docBuilders.join;
|
||||
const hardline = docBuilders.hardline;
|
||||
// const line = docBuilders.line;
|
||||
const softline = docBuilders.softline;
|
||||
const group = docBuilders.group;
|
||||
const indent = docBuilders.indent;
|
||||
// const ifBreak = docBuilders.ifBreak;
|
||||
|
||||
// http://w3c.github.io/html/single-page.html#void-elements
|
||||
const voidTags = {
|
||||
area: true,
|
||||
base: true,
|
||||
br: true,
|
||||
col: true,
|
||||
embed: true,
|
||||
hr: true,
|
||||
img: true,
|
||||
input: true,
|
||||
link: true,
|
||||
meta: true,
|
||||
param: true,
|
||||
source: true,
|
||||
track: true,
|
||||
wbr: true
|
||||
};
|
||||
|
||||
function genericPrint(path, options, print) {
|
||||
const n = path.getValue();
|
||||
if (!n) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (typeof n === "string") {
|
||||
return n;
|
||||
}
|
||||
|
||||
switch (n.type) {
|
||||
case "root": {
|
||||
return concat(path.map(print, "children"));
|
||||
}
|
||||
case "directive": {
|
||||
return concat(["<", n.data, ">", hardline]);
|
||||
}
|
||||
case "text": {
|
||||
return n.data.replace(/\s+/g, " ").trim();
|
||||
}
|
||||
case "tag": {
|
||||
const selfClose = voidTags[n.name] ? ">" : " />";
|
||||
|
||||
const children = [];
|
||||
path.each(childPath => {
|
||||
const child = childPath.getValue();
|
||||
if (child.type !== "text") {
|
||||
children.push(softline);
|
||||
}
|
||||
children.push(childPath.call(print));
|
||||
}, "children");
|
||||
|
||||
return group(
|
||||
concat([
|
||||
"<",
|
||||
n.name,
|
||||
printAttributes(n.attribs),
|
||||
|
||||
n.children.length ? ">" : selfClose,
|
||||
|
||||
indent(concat(children)),
|
||||
n.children.length ? concat([softline, "</", n.name, ">"]) : ""
|
||||
])
|
||||
);
|
||||
}
|
||||
case "comment": {
|
||||
return concat(["<!-- ", n.data.trim(), " -->"]);
|
||||
}
|
||||
default:
|
||||
throw new Error("unknown htmlparser2 type: " + n.type);
|
||||
}
|
||||
}
|
||||
|
||||
function printAttributes(attribs) {
|
||||
const attributeKeys = Object.keys(attribs);
|
||||
return concat([
|
||||
attributeKeys.length ? " " : "",
|
||||
join(
|
||||
" ",
|
||||
attributeKeys.map(name => {
|
||||
if (attribs[name] === "") {
|
||||
return name;
|
||||
}
|
||||
return concat([name, '="', attribs[name], '"']);
|
||||
})
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = genericPrint;
|
|
@ -52,6 +52,8 @@ function getPrintFunction(options) {
|
|||
switch (options.parser) {
|
||||
case "graphql":
|
||||
return require("./printer-graphql");
|
||||
case "parse5":
|
||||
return require("./printer-htmlparser2");
|
||||
case "postcss":
|
||||
return require("./printer-postcss");
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`hello-world.html 1`] = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- A comment -->
|
||||
<h1>Hello World</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body><!-- A comment --><h1>Hello World</h1></body>
|
||||
</html>
|
||||
`;
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- A comment -->
|
||||
<h1>Hello World</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
run_spec(__dirname, { parser: "parse5" });
|
|
@ -16,7 +16,7 @@ function run_spec(dirname, options, additionalParsers) {
|
|||
fs.readdirSync(dirname).forEach(filename => {
|
||||
const extension = extname(filename);
|
||||
if (
|
||||
/^\.([jt]sx?|css|graphql)$/.test(extension) &&
|
||||
/^\.([jt]sx?|css|graphql|html)$/.test(extension) &&
|
||||
filename !== "jsfmt.spec.js"
|
||||
) {
|
||||
const path = dirname + "/" + filename;
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -2,6 +2,10 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@^6.0.46":
|
||||
version "6.0.78"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.78.tgz#5d4a3f579c1524e01ee21bf474e6fba09198f470"
|
||||
|
||||
abab@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
|
||||
|
@ -2746,6 +2750,12 @@ parse-json@^2.2.0:
|
|||
dependencies:
|
||||
error-ex "^1.2.0"
|
||||
|
||||
parse5@3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510"
|
||||
dependencies:
|
||||
"@types/node" "^6.0.46"
|
||||
|
||||
parse5@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
|
||||
|
|
Loading…
Reference in New Issue