feat(html): add parse5/htmlparser2 printer (#2083)
parent
f399e90bc2
commit
d00956d51d
|
@ -98,6 +98,7 @@ function getParserOption() {
|
||||||
value === "babylon" ||
|
value === "babylon" ||
|
||||||
value === "typescript" ||
|
value === "typescript" ||
|
||||||
value === "postcss" ||
|
value === "postcss" ||
|
||||||
|
value === "parse5" ||
|
||||||
value === "graphql"
|
value === "graphql"
|
||||||
) {
|
) {
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"jest-validate": "20.0.3",
|
"jest-validate": "20.0.3",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
|
"parse5": "3.0.2",
|
||||||
"postcss": "^6.0.1",
|
"postcss": "^6.0.1",
|
||||||
"postcss-less": "^1.0.0",
|
"postcss-less": "^1.0.0",
|
||||||
"postcss-media-query-parser": "0.2.3",
|
"postcss-media-query-parser": "0.2.3",
|
||||||
|
|
|
@ -31,6 +31,8 @@ function normalize(options) {
|
||||||
|
|
||||||
if (/\.(css|less|scss)$/.test(filepath)) {
|
if (/\.(css|less|scss)$/.test(filepath)) {
|
||||||
normalized.parser = "postcss";
|
normalized.parser = "postcss";
|
||||||
|
} else if (/\.html$/.test(filepath)) {
|
||||||
|
normalized.parser = "parse5";
|
||||||
} else if (/\.(ts|tsx)$/.test(filepath)) {
|
} else if (/\.(ts|tsx)$/.test(filepath)) {
|
||||||
normalized.parser = "typescript";
|
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";
|
"use strict";
|
||||||
|
|
||||||
function parse(text, opts) {
|
function getParseFunction(opts) {
|
||||||
let parseFunction;
|
switch (opts.parser) {
|
||||||
|
case "flow":
|
||||||
if (opts.parser === "flow") {
|
return eval("require")("./parser-flow");
|
||||||
parseFunction = eval("require")("./parser-flow");
|
case "graphql":
|
||||||
} else if (opts.parser === "graphql") {
|
return eval("require")("./parser-graphql");
|
||||||
parseFunction = eval("require")("./parser-graphql");
|
case "parse5":
|
||||||
} else if (opts.parser === "typescript") {
|
return eval("require")("./parser-parse5");
|
||||||
parseFunction = eval("require")("./parser-typescript");
|
case "postcss":
|
||||||
} else if (opts.parser === "postcss") {
|
return eval("require")("./parser-postcss");
|
||||||
parseFunction = eval("require")("./parser-postcss");
|
case "typescript":
|
||||||
} else {
|
return eval("require")("./parser-typescript");
|
||||||
parseFunction = eval("require")("./parser-babylon");
|
default:
|
||||||
|
return eval("require")("./parser-babylon");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parse(text, opts) {
|
||||||
try {
|
try {
|
||||||
return parseFunction(text);
|
return getParseFunction(opts)(text);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const loc = error.loc;
|
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) {
|
switch (options.parser) {
|
||||||
case "graphql":
|
case "graphql":
|
||||||
return require("./printer-graphql");
|
return require("./printer-graphql");
|
||||||
|
case "parse5":
|
||||||
|
return require("./printer-htmlparser2");
|
||||||
case "postcss":
|
case "postcss":
|
||||||
return require("./printer-postcss");
|
return require("./printer-postcss");
|
||||||
default:
|
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 => {
|
fs.readdirSync(dirname).forEach(filename => {
|
||||||
const extension = extname(filename);
|
const extension = extname(filename);
|
||||||
if (
|
if (
|
||||||
/^\.([jt]sx?|css|graphql)$/.test(extension) &&
|
/^\.([jt]sx?|css|graphql|html)$/.test(extension) &&
|
||||||
filename !== "jsfmt.spec.js"
|
filename !== "jsfmt.spec.js"
|
||||||
) {
|
) {
|
||||||
const path = dirname + "/" + filename;
|
const path = dirname + "/" + filename;
|
||||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -2,6 +2,10 @@
|
||||||
# yarn lockfile v1
|
# 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:
|
abab@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
|
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
|
||||||
|
@ -2746,6 +2750,12 @@ parse-json@^2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
error-ex "^1.2.0"
|
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:
|
parse5@^1.5.1:
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
|
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
|
||||||
|
|
Loading…
Reference in New Issue