From e62528e56e4e4157af5887434f9cc0f64f1d1ae8 Mon Sep 17 00:00:00 2001 From: fisker Date: Tue, 14 Jul 2020 18:48:47 +0800 Subject: [PATCH 1/3] Use `vue-eslint-parser` to parse vue expression --- package.json | 1 + src/common/internal-plugins.js | 2 +- src/language-html/printer-html.js | 5 +++- src/language-js/parser-vue.js | 30 +++++++++++++++++++ src/language-js/postprocess.js | 49 +++++++++++++++++-------------- src/language-js/printer-estree.js | 14 +++++++-- yarn.lock | 23 ++++++++++++++- 7 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 src/language-js/parser-vue.js diff --git a/package.json b/package.json index 5252cfbca217..ed9a7bd2202c 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "unicode-regex": "3.0.0", "unified": "9.0.0", "vnopts": "1.0.2", + "vue-eslint-parser": "7.1.0", "yaml-unist-parser": "1.2.1" }, "devDependencies": { diff --git a/src/common/internal-plugins.js b/src/common/internal-plugins.js index 7c0cecdf6208..c414e2f13eaf 100644 --- a/src/common/internal-plugins.js +++ b/src/common/internal-plugins.js @@ -29,7 +29,7 @@ module.exports = [ return require("../language-js/parser-babel").parsers.__js_expression; }, get __vue_expression() { - return require("../language-js/parser-babel").parsers.__vue_expression; + return require("../language-js/parser-vue").parsers.__vue_expression; }, get __vue_event_binding() { return require("../language-js/parser-babel").parsers diff --git a/src/language-html/printer-html.js b/src/language-html/printer-html.js index b6b1fede3b72..c60e18196b41 100644 --- a/src/language-html/printer-html.js +++ b/src/language-html/printer-html.js @@ -1011,13 +1011,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 132d37602723..505933af1382 100644 --- a/src/language-js/postprocess.js +++ b/src/language-js/postprocess.js @@ -13,6 +13,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" && options.parser !== "flow") { const startOffsetsOfTypeCastedNodes = new Set(); @@ -21,7 +29,7 @@ function postprocess(ast, options) { // E.g.: /** @type {Foo} */ (foo).bar(); // Let's use the fact that those ancestors and ParenthesizedExpression have the same start offset. - visitNode(ast, (node) => { + ast = visitNode(ast, (node) => { if ( node.leadingComments && node.leadingComments.some(isTypeCastComment) @@ -30,7 +38,7 @@ function postprocess(ast, options) { } }); - visitNode(ast, (node) => { + ast = visitNode(ast, (node) => { if (node.type === "ParenthesizedExpression") { const start = locStart(node); if (!startOffsetsOfTypeCastedNodes.has(start)) { @@ -46,7 +54,7 @@ function postprocess(ast, options) { }); } - visitNode(ast, (node) => { + ast = visitNode(ast, (node) => { switch (node.type) { case "LogicalExpression": { // We remove unneeded parens around same-operator LogicalExpressions @@ -133,31 +141,28 @@ function postprocess(ast, options) { } } -function visitNode(node, fn, parent, property) { - if (!node || typeof node !== "object") { - return; - } +function visitNode(node, fn) { + let entries; if (Array.isArray(node)) { - for (let i = 0; i < node.length; i++) { - visitNode(node[i], fn, node, i); - } - return; - } - - if (typeof node.type !== "string") { - return; + entries = node.entries(); + } else if ( + node && + typeof node === "object" && + typeof node.type === "string" + ) { + entries = Object.entries(node); + } else { + return node; } - for (const key of Object.keys(node)) { - visitNode(node[key], fn, node, key); + for (const [key, child] of entries) { + if (key !== "parent") { + node[key] = visitNode(child, fn); + } } - const replacement = fn(node); - - if (replacement) { - parent[property] = replacement; - } + return fn(node) || node; } function isUnbalancedLogicalTree(node) { diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index df1e70c24c5e..1c63517c5295 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -941,7 +941,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"; @@ -3474,7 +3479,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 3572f1ef1368..2da419cc0178 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3390,6 +3390,15 @@ eslint@7.4.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +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" + espree@^7.0.0, espree@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" @@ -3404,7 +3413,7 @@ esprima@^4.0.0, esprima@^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.0.1, esquery@^1.2.0: 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== @@ -7856,6 +7865,18 @@ vscode-uri@^2.1.1: 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" From 7c7fe653c8b62a1ccdfe1feb9174d1d9c44d1f3f Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 5 Nov 2020 19:01:15 +0800 Subject: [PATCH 2/3] Update lock --- src/language-js/postprocess.js | 6 ------ yarn.lock | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/language-js/postprocess.js b/src/language-js/postprocess.js index e52f95339aef..10ab243ba3d2 100644 --- a/src/language-js/postprocess.js +++ b/src/language-js/postprocess.js @@ -154,11 +154,6 @@ function postprocess(ast, options) { } } -<<<<<<< HEAD -function visitNode(node, fn) { - let entries; - -======= // This is a workaround to transform `ChainExpression` from `espree` into // `babel` shape AST, we should do the opposite, since `ChainExpression` is the // standard `estree` AST for `optional chaining` @@ -177,7 +172,6 @@ function transformChainExpression(node) { function visitNode(node, fn) { let entries; ->>>>>>> master if (Array.isArray(node)) { entries = node.entries(); } else if ( 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" From 63773c81d9f58bd9d212c63879b3e61093df646a Mon Sep 17 00:00:00 2001 From: fisker Date: Fri, 6 Nov 2020 00:43:42 +0800 Subject: [PATCH 3/3] Bundle --- scripts/build/config.js | 3 +++ 1 file changed, 3 insertions(+) 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