diff --git a/package.json b/package.json index 94875c42634b..f86faa9b3bea 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "unicode-regex": "3.0.0", "unified": "9.2.0", "vnopts": "1.0.2", + "vue-eslint-parser": "7.1.0", "yaml-unist-parser": "1.3.1" }, "devDependencies": { diff --git a/scripts/build/config.js b/scripts/build/config.js index 5e527e6a4932..8b1b909b76e5 100644 --- a/scripts/build/config.js +++ b/scripts/build/config.js @@ -51,6 +51,9 @@ const parsers = [ { input: "src/language-js/parser-angular.js", }, + { + input: "src/language-js/parser-vue.js", + }, { input: "src/language-css/parser-postcss.js", // postcss has dependency cycles that don't work with rollup diff --git a/src/language-html/printer-html.js b/src/language-html/printer-html.js index 0beeea66333c..dece72297ae1 100644 --- a/src/language-html/printer-html.js +++ b/src/language-html/printer-html.js @@ -1019,13 +1019,16 @@ function printEmbeddedAttributeValue(node, originalTextToDoc, options) { : root.type === "JsExpressionRoot" ? root.node : root; + if ( rootNode && (rootNode.type === "ObjectExpression" || rootNode.type === "ArrayExpression" || (options.parser === "__vue_expression" && (rootNode.type === "TemplateLiteral" || - rootNode.type === "StringLiteral"))) + rootNode.type === "StringLiteral" || + (rootNode.type === "Literal" && + typeof rootNode.value === "string")))) ) { shouldHug = true; } diff --git a/src/language-js/parser-vue.js b/src/language-js/parser-vue.js new file mode 100644 index 000000000000..91c33f80d51b --- /dev/null +++ b/src/language-js/parser-vue.js @@ -0,0 +1,30 @@ +"use strict"; + +const locFns = require("./loc"); +const postprocess = require("./postprocess"); + +function parseExpression(text, parsers, options) { + const { parse } = require("vue-eslint-parser"); + let ast = parse(``); + ast = postprocess(ast, { ...options, originalText: text }); + + const {templateBody} = ast; + const {errors, comments} = templateBody; + if (errors.length) { + throw errors[0] + } + + const { expression } = templateBody.children[0]; + expression.comments = comments; + return expression; +} + +module.exports = { + parsers: { + __vue_expression: { + astFormat: "estree", + parse: parseExpression, + ...locFns, + }, + }, +}; diff --git a/src/language-js/postprocess.js b/src/language-js/postprocess.js index 3efece636707..10ab243ba3d2 100644 --- a/src/language-js/postprocess.js +++ b/src/language-js/postprocess.js @@ -17,6 +17,14 @@ function postprocess(ast, options) { includeShebang(ast, options); } + if (options.parser === "__vue_expression") { + ast = visitNode(ast, (node) => { + if (node && node.type) { + delete node.parent; + } + }); + } + // Keep Babel's non-standard ParenthesizedExpression nodes only if they have Closure-style type cast comments. if ( options.parser !== "typescript" && @@ -177,7 +185,9 @@ function visitNode(node, fn) { } for (const [key, child] of entries) { - node[key] = visitNode(child, fn); + if (key !== "parent") { + node[key] = visitNode(child, fn); + } } return fn(node) || node; diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 3f0fd94412ff..af412a18b6b5 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -962,7 +962,12 @@ function printPathNoParens(path, options, print, args) { case "NewExpression": case "ImportExpression": case "OptionalCallExpression": - case "CallExpression": { + case "CallExpression": + case "VFilter": { + if (n.type === "VFilter" && !n.arguments.length) { + return path.call(print, "callee"); + } + const isNew = n.type === "NewExpression"; const isDynamicImport = n.type === "ImportExpression"; @@ -3550,7 +3555,12 @@ function printPathNoParens(path, options, print, args) { "): ", path.call(print, "typeAnnotation"), ]); - + case "VFilterSequenceExpression": + const operator = concat([line, "| "]); + return concat([ + path.call(print, "expression"), + indent(concat([operator, join(operator, path.map(print, "filters"))])), + ]); default: /* istanbul ignore next */ throw new Error("unknown type: " + JSON.stringify(n.type)); diff --git a/yarn.lock b/yarn.lock index d348230b2a82..8e09b5957b6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3286,12 +3286,21 @@ espree@7.3.0, espree@^7.3.0: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.3.0" +espree@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.2.0, esquery@^1.3.1: +esquery@^1.0.1, esquery@^1.2.0, esquery@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== @@ -7401,6 +7410,18 @@ vscode-uri@^2.1.2: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c" integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A== +vue-eslint-parser@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.1.0.tgz#9cdbcc823e656b087507a1911732b867ac101e83" + integrity sha512-Kr21uPfthDc63nDl27AGQEhtt9VrZ9nkYk/NTftJ2ws9XiJwzJJCnCr3AITQ2jpRMA0XPGDECxYH8E027qMK9Q== + dependencies: + debug "^4.1.1" + eslint-scope "^5.0.0" + eslint-visitor-keys "^1.1.0" + espree "^6.2.1" + esquery "^1.0.1" + lodash "^4.17.15" + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"