Adds LWC Parser to support unquoted interop attributes (#5800)

This pull requests adds a new parser option `lwc`. This is the same as the HTML parser, but it adds support for unquoted HTML attributes per the needs of LWC. See: #5627
master
Nathan Totten 2019-02-01 00:58:50 -05:00 committed by Ika
parent 154435bb36
commit a093bb3f7b
19 changed files with 239 additions and 16 deletions

View File

@ -68,3 +68,19 @@ Examples:
| bordered | Toggles rendering of the border around the list | boolean | false |
| itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - |
```
- LWC: Add support for Lightning Web Components ([#5800] by [@ntotten])
Supports [Lightning Web Components (LWC)](https://developer.salesforce.com/docs/component-library/documentation/lwc) template format for HTML attributes by adding a new parser called `lwc`.
<!-- prettier-ignore -->
```html
// Input
<my-element data-for={value}></my-element>
// Output (Prettier stable)
<my-element data-for="{value}"></my-element>
// Output (Prettier master)
<my-element data-for={value}></my-element>
```

View File

@ -196,6 +196,7 @@ Valid options:
- `"html"` (via [angular-html-parser](https://github.com/ikatyang/angular-html-parser/tree/master/packages/angular-html-parser)) _First available in 1.15.0_
- `"vue"` (same parser as `"html"`, but also formats vue-specific syntax) _First available in 1.10.0_
- `"angular"` (same parser as `"html"`, but also formats angular-specific syntax via [angular-estree-parser](https://github.com/ikatyang/angular-estree-parser)) _First available in 1.15.0_
- `"lwc"` (same parser as `"html"`, but also formats LWC-specific syntax for unquoted template attributes) _First available in 1.17.0_
- `"yaml"` (via [yaml](https://github.com/eemeli/yaml) and [yaml-unist-parser](https://github.com/ikatyang/yaml-unist-parser)) _First available in 1.14.0_
[Custom parsers](api.md#custom-parser-api) are also supported. _First available in v1.5.0_

View File

@ -157,6 +157,10 @@ module.exports = [
// Angular
get angular() {
return eval("require")("../language-html/parser-html").parsers.angular;
},
// Lightning Web Components
get lwc() {
return eval("require")("../language-html/parser-html").parsers.lwc;
}
}
},

View File

@ -508,7 +508,8 @@ function printString(raw, options, isDirectiveLiteral) {
options.parser === "scss" ||
options.parentParser === "html" ||
options.parentParser === "vue" ||
options.parentParser === "angular"
options.parentParser === "angular" ||
options.parentParser === "lwc"
)
);
}

View File

@ -28,6 +28,17 @@ const languages = [
]
}
}),
createLanguage(require("linguist-languages/data/html"), {
override: {
name: "Lightning Web Components",
since: "1.17.0",
parsers: ["lwc"],
vscodeLanguageIds: ["html"],
extensions: [],
filenames: []
}
}),
createLanguage(require("linguist-languages/data/vue"), {
override: {
since: "1.10.0",

View File

@ -297,6 +297,7 @@ module.exports = {
vue: createParser({
recognizeSelfClosing: true,
isTagNameCaseSensitive: true
})
}),
lwc: createParser()
}
};

View File

@ -123,6 +123,21 @@ function embed(path, print, textToDoc, options) {
return concat([node.rawName, "=", node.value]);
}
// lwc: html`<my-element data-for={value}></my-elememt>`
if (options.parser === "lwc") {
const interpolationRegex = /^\{[\s\S]*\}$/;
if (
interpolationRegex.test(
options.originalText.slice(
node.valueSpan.start.offset,
node.valueSpan.end.offset
)
)
) {
return concat([node.rawName, "=", node.value]);
}
}
const embeddedAttributeValueDoc = printEmbeddedAttributeValue(
node,
(code, opts) =>

View File

@ -160,7 +160,8 @@ const options = {
description: "Handlebars"
},
{ value: "html", since: "1.15.0", description: "HTML" },
{ value: "angular", since: "1.15.0", description: "Angular" }
{ value: "angular", since: "1.15.0", description: "Angular" },
{ value: "lwc", since: "1.17.0", description: "Lightning Web Components" }
]
},
plugins: {

View File

@ -2,7 +2,7 @@
exports[`empty 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular"]
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
@ -14,7 +14,7 @@ printWidth: 80
exports[`newline 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular"]
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
@ -27,7 +27,7 @@ printWidth: 80
exports[`space 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular"]
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================
@ -40,7 +40,7 @@ printWidth: 80
exports[`space-newline 1`] = `
====================================options=====================================
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular"]
parsers: ["flow", "babel", "babel-flow", "typescript", "css", "less", "scss", "json", "json5", "json-stringify", "graphql", "markdown", "mdx", "vue", "yaml", "html", "angular", "lwc"]
printWidth: 80
| printWidth
=====================================input======================================

View File

@ -0,0 +1,117 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`attributes.html 1`] = `
====================================options=====================================
parser: "lwc"
parsers: ["lwc"]
printWidth: 80
| printWidth
=====================================input======================================
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}>
=====================================output=====================================
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}></a>
================================================================================
`;
exports[`attributes.html 2`] = `
====================================options=====================================
parser: "lwc"
parsers: ["lwc"]
printWidth: 80
trailingComma: "es5"
| printWidth
=====================================input======================================
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}>
=====================================output=====================================
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}></a>
================================================================================
`;
exports[`attributes.html 3`] = `
====================================options=====================================
parser: "lwc"
parsers: ["lwc"]
printWidth: 80
semi: false
| printWidth
=====================================input======================================
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}>
=====================================output=====================================
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}></a>
================================================================================
`;

View File

@ -0,0 +1,13 @@
<template>
<div
data-for={value}
data-for={value[0]}
data-for={value.toString()}
data-for={value()}
class="test"
></div>
</template>
<template if:true={value.error}>
<c-error-panel errors={value.error}></c-error-panel>
</template>
<a href="#" onclick={aFunction}>

View File

@ -0,0 +1,3 @@
run_spec(__dirname, ["lwc"], { parser: "lwc" });
run_spec(__dirname, ["lwc"], { parser: "lwc", trailingComma: "es5" });
run_spec(__dirname, ["lwc"], { parser: "lwc", semi: false });

View File

@ -72,7 +72,7 @@ Format options:
Defaults to false.
--jsx-single-quote Use single quotes in JSX.
Defaults to false.
--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular>
--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
--print-width <int> The line length where Prettier will try wrap.
Defaults to 80.
@ -162,7 +162,7 @@ exports[`show warning with --help not-found (typo) (stderr) 1`] = `
`;
exports[`show warning with --help not-found (typo) (stdout) 1`] = `
"--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular>
"--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
@ -185,6 +185,7 @@ Valid options:
yaml YAML
html HTML
angular Angular
lwc Lightning Web Components
"
`;
@ -221,7 +222,7 @@ Format options:
Defaults to false.
--jsx-single-quote Use single quotes in JSX.
Defaults to false.
--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular>
--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
--print-width <int> The line length where Prettier will try wrap.
Defaults to 80.

View File

@ -332,7 +332,7 @@ exports[`show detailed usage with --help no-semi (write) 1`] = `Array []`;
exports[`show detailed usage with --help parser (stderr) 1`] = `""`;
exports[`show detailed usage with --help parser (stdout) 1`] = `
"--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular>
"--parser <flow|babel|babel-flow|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular|lwc>
Which parser to use.
@ -355,6 +355,7 @@ Valid options:
yaml YAML
html HTML
angular Angular
lwc Lightning Web Components
"
`;

View File

@ -224,6 +224,12 @@ This option cannot be used with --range-start and --range-end.",
"angular",
],
},
Object {
"description": "Lightning Web Components",
"enum": Array [
"lwc",
],
},
],
},
"pluginSearchDirs": Object {

View File

@ -448,12 +448,15 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
\\"flow\\",
],
\\"JavaScript\\": Array [
@@ -25,10 +37,13 @@
@@ -25,10 +37,16 @@
\\"flow\\",
],
\\"Less\\": Array [
\\"less\\",
],
+ \\"Lightning Web Components\\": Array [
+ \\"lwc\\",
+ ],
+ \\"MDX\\": Array [
+ \\"mdx\\",
+ ],
@ -462,7 +465,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
],
\\"PostCSS\\": Array [
\\"css\\",
@@ -37,12 +52,26 @@
@@ -37,12 +55,26 @@
\\"scss\\",
],
\\"TypeScript\\": Array [
@ -489,7 +492,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
\\"type\\": \\"boolean\\",
},
\\"cursorOffset\\": Object {
@@ -52,37 +81,76 @@
@@ -52,37 +84,77 @@
\\"start\\": -1,
\\"step\\": 1,
},
@ -550,6 +553,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
+ \\"yaml\\",
+ \\"html\\",
+ \\"angular\\",
+ \\"lwc\\",
],
- \\"default\\": \\"babylon\\",
+ \\"default\\": undefined,
@ -568,7 +572,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
\\"range\\": Object {
\\"end\\": Infinity,
\\"start\\": 0,
@@ -90,14 +158,15 @@
@@ -90,14 +162,15 @@
},
\\"type\\": \\"int\\",
},
@ -919,6 +923,22 @@ exports[`CLI --support-info (stdout) 1`] = `
\\"type\\": \\"markup\\",
\\"vscodeLanguageIds\\": [\\"html\\"]
},
{
\\"aceMode\\": \\"html\\",
\\"aliases\\": [\\"xhtml\\"],
\\"codemirrorMimeType\\": \\"text/html\\",
\\"codemirrorMode\\": \\"htmlmixed\\",
\\"color\\": \\"#e34c26\\",
\\"extensions\\": [],
\\"filenames\\": [],
\\"linguistLanguageId\\": 146,
\\"name\\": \\"Lightning Web Components\\",
\\"parsers\\": [\\"lwc\\"],
\\"since\\": \\"1.17.0\\",
\\"tmScope\\": \\"text.html.basic\\",
\\"type\\": \\"markup\\",
\\"vscodeLanguageIds\\": [\\"html\\"]
},
{
\\"aceMode\\": \\"html\\",
\\"color\\": \\"#2c3e50\\",
@ -1109,7 +1129,12 @@ exports[`CLI --support-info (stdout) 1`] = `
{ \\"description\\": \\"Vue\\", \\"since\\": \\"1.10.0\\", \\"value\\": \\"vue\\" },
{ \\"description\\": \\"YAML\\", \\"since\\": \\"1.14.0\\", \\"value\\": \\"yaml\\" },
{ \\"description\\": \\"HTML\\", \\"since\\": \\"1.15.0\\", \\"value\\": \\"html\\" },
{ \\"description\\": \\"Angular\\", \\"since\\": \\"1.15.0\\", \\"value\\": \\"angular\\" }
{ \\"description\\": \\"Angular\\", \\"since\\": \\"1.15.0\\", \\"value\\": \\"angular\\" },
{
\\"description\\": \\"Lightning Web Components\\",
\\"since\\": \\"1.17.0\\",
\\"value\\": \\"lwc\\"
}
],
\\"description\\": \\"Which parser to use.\\",
\\"name\\": \\"parser\\",

View File

@ -285,6 +285,7 @@ export default function(parser) {
].join("\n");
case "html":
case "angular":
case "lwc":
return [
"<!DOCTYPE html>",
'<HTML CLASS="no-js mY-ClAsS">',

View File

@ -47,6 +47,7 @@ function getMarkdownSyntax(options) {
case "glimmer":
return "hbs";
case "angular":
case "lwc":
return "html";
default:
return options.parser;

View File

@ -137,6 +137,11 @@ var parsers = {
get angular() {
importScriptOnce("lib/parser-html.js");
return prettierPlugins.html.parsers.angular;
},
// Lightning Web Components
get lwc() {
importScriptOnce("lib/parser-html.js");
return prettierPlugins.html.parsers.lwc;
}
};