Move ts script check into embed print (#14559)

This commit is contained in:
fisker Cheung authored and GitHub committed 2023-03-27 14:22:54 +08:00
1 parent 919670df68
commit bae1eb4a14
5 files changed
+76 -59

No files matched your search

+42 -41
View File
@@ -28,17 +28,18 @@ import {
inferElementParser,
htmlTrimPreserveIndentation,
dedentString,
unescapeQuoteEntities,
isVueSlotAttribute,
isVueSfcBindingsAttribute,
getTextValueParts,
getUnescapedAttributeValue,
} from "./utils/index.js";
import isVueSfcWithTypescriptScript from "./utils/is-vue-sfc-with-typescript-script.js";
import getNodeContent from "./get-node-content.js";
async function printEmbeddedAttributeValue(node, htmlTextToDoc, options) {
async function printEmbeddedAttributeValue(path, htmlTextToDoc, options) {
const { node } = path;
const isKeyMatched = (patterns) =>
new RegExp(patterns.join("|")).test(node.fullName);
const getValue = () => unescapeQuoteEntities(node.value);
let shouldHug = false;
@@ -77,40 +78,43 @@ async function printEmbeddedAttributeValue(node, htmlTextToDoc, options) {
__embeddedInHtml: true,
...opts,
});
const value = getUnescapedAttributeValue(node);
if (
node.fullName === "srcset" &&
(node.parent.fullName === "img" || node.parent.fullName === "source")
) {
return printExpand(printImgSrcset(getValue()));
return printExpand(printImgSrcset(value));
}
if (node.fullName === "class" && !options.parentParser) {
const value = getValue();
if (!value.includes("{{")) {
return printClassNames(value);
}
if (
node.fullName === "class" &&
!options.parentParser &&
!value.includes("{{")
) {
return printClassNames(value);
}
if (node.fullName === "style" && !options.parentParser) {
const value = getValue();
if (!value.includes("{{")) {
return printExpand(
await attributeTextToDoc(value, {
parser: "css",
__isHTMLStyleAttribute: true,
})
);
}
if (
node.fullName === "style" &&
!options.parentParser &&
!value.includes("{{")
) {
return printExpand(
await attributeTextToDoc(value, {
parser: "css",
__isHTMLStyleAttribute: true,
})
);
}
if (options.parser === "vue") {
if (node.fullName === "v-for") {
return printVueFor(getValue(), attributeTextToDoc, options);
return printVueFor(path, attributeTextToDoc, options);
}
if (isVueSlotAttribute(node) || isVueSfcBindingsAttribute(node, options)) {
return printVueBindings(getValue(), attributeTextToDoc, options);
return printVueBindings(path, attributeTextToDoc, options);
}
/**
@@ -131,12 +135,11 @@ async function printEmbeddedAttributeValue(node, htmlTextToDoc, options) {
const jsExpressionBindingPatterns = ["^v-"];
if (isKeyMatched(vueEventBindingPatterns)) {
const value = getValue();
const parser = isVueEventBindingExpression(value)
? options.__should_parse_vue_template_with_ts
? isVueSfcWithTypescriptScript(path, options)
? "__ts_expression"
: "__js_expression"
: options.__should_parse_vue_template_with_ts
: isVueSfcWithTypescriptScript(path, options)
? "__vue_ts_event_binding"
: "__vue_event_binding";
return printMaybeHug(await attributeTextToDoc(value, { parser }));
@@ -144,8 +147,8 @@ async function printEmbeddedAttributeValue(node, htmlTextToDoc, options) {
if (isKeyMatched(vueExpressionBindingPatterns)) {
return printMaybeHug(
await attributeTextToDoc(getValue(), {
parser: options.__should_parse_vue_template_with_ts
await attributeTextToDoc(value, {
parser: isVueSfcWithTypescriptScript(path, options)
? "__vue_ts_expression"
: "__vue_expression",
})
@@ -154,8 +157,8 @@ async function printEmbeddedAttributeValue(node, htmlTextToDoc, options) {
if (isKeyMatched(jsExpressionBindingPatterns)) {
return printMaybeHug(
await attributeTextToDoc(getValue(), {
parser: options.__should_parse_vue_template_with_ts
await attributeTextToDoc(value, {
parser: isVueSfcWithTypescriptScript(path, options)
? "__ts_expression"
: "__js_expression",
})
@@ -196,33 +199,29 @@ async function printEmbeddedAttributeValue(node, htmlTextToDoc, options) {
const ngI18nPatterns = ["^i18n(-.+)?$"];
if (isKeyMatched(ngStatementBindingPatterns)) {
return printMaybeHug(
await ngTextToDoc(getValue(), { parser: "__ng_action" })
);
return printMaybeHug(await ngTextToDoc(value, { parser: "__ng_action" }));
}
if (isKeyMatched(ngExpressionBindingPatterns)) {
return printMaybeHug(
await ngTextToDoc(getValue(), { parser: "__ng_binding" })
await ngTextToDoc(value, { parser: "__ng_binding" })
);
}
if (isKeyMatched(ngI18nPatterns)) {
const value = getValue().trim();
return printExpand(
fill(getTextValueParts(node, value)),
fill(getTextValueParts(node, value.trim())),
!value.includes("@@")
);
}
if (isKeyMatched(ngDirectiveBindingPatterns)) {
return printMaybeHug(
await ngTextToDoc(getValue(), { parser: "__ng_directive" })
await ngTextToDoc(value, { parser: "__ng_directive" })
);
}
const interpolationRegex = /{{(.+?)}}/s;
const value = getValue();
if (interpolationRegex.test(value)) {
const parts = [];
for (const [index, part] of value.split(interpolationRegex).entries()) {
@@ -341,10 +340,12 @@ function embed(path, options) {
textToDocOptions.parser = "__ng_interpolation";
textToDocOptions.trailingComma = "none";
} else if (options.parser === "vue") {
textToDocOptions.parser =
options.__should_parse_vue_template_with_ts
? "__vue_ts_expression"
: "__vue_expression";
textToDocOptions.parser = isVueSfcWithTypescriptScript(
path,
options
)
? "__vue_ts_expression"
: "__vue_expression";
} else {
textToDocOptions.parser = "__js_expression";
}
@@ -394,7 +395,7 @@ function embed(path, options) {
return async (textToDoc) => {
const embeddedAttributeValueDoc = await printEmbeddedAttributeValue(
node,
path,
(code, opts) =>
// strictly prefer single quote to avoid unnecessary html entity escape
textToDoc(code, {
-12
View File
@@ -9,7 +9,6 @@ import {
isLeadingSpaceSensitiveNode,
isTrailingSpaceSensitiveNode,
isWhitespaceSensitiveNode,
isVueScriptTag,
} from "./utils/index.js";
const PREPROCESS_PIPELINE = [
@@ -23,7 +22,6 @@ const PREPROCESS_PIPELINE = [
addHasHtmComponentClosingTag,
addIsSpaceSensitive,
mergeSimpleElementIntoText,
markTsScript,
];
function preprocess(ast, options) {
@@ -403,14 +401,4 @@ function addIsSpaceSensitive(ast, options) {
});
}
function markTsScript(ast, options) {
options.__should_parse_vue_template_with_ts =
options.parser === "vue" &&
ast.children.some(
(child) =>
isVueScriptTag(child, options) &&
["ts", "typescript"].includes(child.attrMap.lang)
);
}
export default preprocess;
+9 -6
View File
@@ -1,4 +1,7 @@
import { group } from "../document/builders.js";
import { getUnescapedAttributeValue } from "./utils/index.js";
import isVueSfcWithTypescriptScript from "./utils/is-vue-sfc-with-typescript-script.js";
/**
* @typedef {import("../document/builders.js").Doc} Doc
*/
@@ -9,14 +12,14 @@ import { group } from "../document/builders.js";
* v-for="(..., ...) in ..."
* v-for="(..., ...) of ..."
*
* @param {*} value
* @param {(code: string, opts: *) => Doc} attributeTextToDoc
* @param {*} options
* @returns {Promise<Doc>}
*/
async function printVueFor(value, attributeTextToDoc, options) {
async function printVueFor(path, attributeTextToDoc, options) {
const value = getUnescapedAttributeValue(path.node);
const { left, operator, right } = parseVueFor(value);
const parseWithTs = options.__should_parse_vue_template_with_ts;
const parseWithTs = isVueSfcWithTypescriptScript(path, options);
return [
group(
await attributeTextToDoc(`function _(${left}) {}`, {
@@ -80,14 +83,14 @@ function parseVueFor(value) {
}
/**
* @param {*} value
* @param {(code: string, opts: *) => Doc} attributeTextToDoc
* @param {*} options
* @returns {Doc}
*/
function printVueBindings(value, attributeTextToDoc, options) {
function printVueBindings(path, attributeTextToDoc, options) {
const value = getUnescapedAttributeValue(path.node);
return attributeTextToDoc(`function _(${value}) {}`, {
parser: options.__should_parse_vue_template_with_ts ? "babel-ts" : "babel",
parser: isVueSfcWithTypescriptScript(path, options) ? "babel-ts" : "babel",
__isVueBindings: true,
});
}
+5
View File
@@ -551,6 +551,10 @@ function unescapeQuoteEntities(text) {
return text.replaceAll("&apos;", "'").replaceAll("&quot;", '"');
}
function getUnescapedAttributeValue(node) {
return unescapeQuoteEntities(node.value);
}
// top-level elements (excluding <template>, <style> and <script>) in Vue SFC are considered custom block
// See https://vue-loader.vuejs.org/spec.html for detail
const vueRootElementsSet = new Set(["template", "style", "script"]);
@@ -650,4 +654,5 @@ export {
unescapeQuoteEntities,
getTextValueParts,
htmlWhitespaceUtils,
getUnescapedAttributeValue,
};
@@ -0,0 +1,20 @@
import { isVueScriptTag } from "./index.js";
const cache = new WeakMap();
function isVueSfcWithTypescriptScript(path, options) {
const { root } = path;
if (!cache.has(root)) {
cache.set(
root,
root.children.some(
(child) =>
isVueScriptTag(child, options) &&
["ts", "typescript"].includes(child.attrMap.lang)
)
);
}
return cache.get(root);
}
export default isVueSfcWithTypescriptScript;