@vue-macros/common
Version:
common feature from Vue Macros.
372 lines (365 loc) • 11.5 kB
JavaScript
// src/index.ts
export * from "magic-string-ast";
export * from "ast-kit";
import {
createFilter as createFilter2,
normalizePath
} from "unplugin-utils";
// src/ast.ts
import { walkIdentifiers } from "@vue/compiler-sfc";
import { isFunctionType, isLiteralType, resolveObjectKey } from "ast-kit";
function checkInvalidScopeReference(node, method, setupBindings) {
if (!node) return;
walkIdentifiers(node, (id) => {
if (setupBindings.includes(id.name))
throw new SyntaxError(
`\`${method}()\` in <script setup> cannot reference locally declared variables (${id.name}) because it will be hoisted outside of the setup() function.`
);
});
}
function isStaticExpression(node, options = {}) {
const { magicComment, fn, object, objectMethod, array, unary, regex } = options;
if (magicComment && node.leadingComments?.some(
(comment) => comment.value.trim() === magicComment
))
return true;
else if (fn && isFunctionType(node)) return true;
switch (node.type) {
case "UnaryExpression":
return !!unary && isStaticExpression(node.argument, options);
case "LogicalExpression":
// 1 > 2
case "BinaryExpression":
return isStaticExpression(node.left, options) && isStaticExpression(node.right, options);
case "ConditionalExpression":
return isStaticExpression(node.test, options) && isStaticExpression(node.consequent, options) && isStaticExpression(node.alternate, options);
case "SequenceExpression":
// (1, 2)
case "TemplateLiteral":
return node.expressions.every((expr) => isStaticExpression(expr, options));
case "ArrayExpression":
return !!array && node.elements.every(
(element) => element && isStaticExpression(element, options)
);
case "ObjectExpression":
return !!object && node.properties.every((prop) => {
if (prop.type === "SpreadElement") {
return prop.argument.type === "ObjectExpression" && isStaticExpression(prop.argument, options);
} else if (!isLiteralType(prop.key) && prop.computed) {
return false;
} else if (prop.type === "ObjectProperty" && !isStaticExpression(prop.value, options)) {
return false;
}
if (prop.type === "ObjectMethod" && !objectMethod) {
return false;
}
return true;
});
case "ParenthesizedExpression":
// (1)
case "TSNonNullExpression":
// 1!
case "TSAsExpression":
// 1 as number
case "TSTypeAssertion":
// (<number>2)
case "TSSatisfiesExpression":
return isStaticExpression(node.expression, options);
case "RegExpLiteral":
return !!regex;
}
if (isLiteralType(node)) return true;
return false;
}
function isStaticObjectKey(node) {
return node.properties.every((prop) => {
if (prop.type === "SpreadElement") {
return prop.argument.type === "ObjectExpression" && isStaticObjectKey(prop.argument);
}
return !prop.computed || isLiteralType(prop.key);
});
}
function resolveObjectExpression(node) {
const maps = /* @__PURE__ */ Object.create(null);
for (const property of node.properties) {
if (property.type === "SpreadElement") {
if (property.argument.type !== "ObjectExpression")
return void 0;
Object.assign(maps, resolveObjectExpression(property.argument));
} else {
const key = resolveObjectKey(property);
maps[key] = property;
}
}
return maps;
}
var importedMap = /* @__PURE__ */ new WeakMap();
var HELPER_PREFIX = "__MACROS_";
function importHelperFn(s, offset, imported, local = imported, from = "vue") {
const cacheKey = `${from}@${imported}`;
if (!importedMap.get(s)?.has(cacheKey)) {
s.appendLeft(
offset,
`
import ${imported === "default" ? HELPER_PREFIX + local : `{ ${imported} as ${HELPER_PREFIX + local} }`} from ${JSON.stringify(from)};`
);
if (!importedMap.has(s)) {
importedMap.set(s, /* @__PURE__ */ new Set([cacheKey]));
} else {
importedMap.get(s).add(cacheKey);
}
}
return `${HELPER_PREFIX}${local}`;
}
// src/constants.ts
var DEFINE_PROPS = "defineProps";
var DEFINE_PROPS_DOLLAR = "$defineProps";
var DEFINE_PROPS_REFS = "definePropsRefs";
var DEFINE_EMITS = "defineEmits";
var WITH_DEFAULTS = "withDefaults";
var DEFINE_OPTIONS = "defineOptions";
var DEFINE_MODELS = "defineModels";
var DEFINE_MODELS_DOLLAR = "$defineModels";
var DEFINE_SETUP_COMPONENT = "defineSetupComponent";
var DEFINE_RENDER = "defineRender";
var DEFINE_SLOTS = "defineSlots";
var DEFINE_STYLEX = "defineStyleX";
var DEFINE_PROP = "defineProp";
var DEFINE_PROP_DOLLAR = "$defineProp";
var DEFINE_EMIT = "defineEmit";
var REPO_ISSUE_URL = `${"https://github.com/vue-macros/vue-macros"}/issues`;
var REGEX_SRC_FILE = /\.[cm]?[jt]sx?$/;
var REGEX_SETUP_SFC = /\.setup\.[cm]?[jt]sx?$/;
var REGEX_SETUP_SFC_SUB = /\.setup\.[cm]?[jt]sx?((?!(? = 2 && version < 3 ? Math.trunc(version) : version;
} else {
return defaultVersion;
}
}
// src/error.ts
var TransformError = class extends SyntaxError {
constructor(message) {
super(message);
this.message = message;
this.name = "TransformError";
}
};
// src/unplugin.ts
import {
createFilter as createRollupFilter
} from "unplugin-utils";
function createFilter(options) {
return createRollupFilter(options.include, options.exclude);
}
var VUE_PLUGINS = ["vite:vue", "unplugin-vue"];
function getVuePluginApi(plugins) {
const vuePlugin = (plugins || []).find((p) => VUE_PLUGINS.includes(p.name));
if (!vuePlugin)
throw new Error(
"Cannot find Vue plugin (@vitejs/plugin-vue or unplugin-vue). Please make sure to add it before using Vue Macros."
);
const api = vuePlugin.api;
if (!api?.version) {
throw new Error(
"The Vue plugin is not supported (@vitejs/plugin-vue or unplugin-vue). Please make sure version > 4.3.4."
);
}
return api;
}
var FilterFileType = /* @__PURE__ */ ((FilterFileType2) => {
FilterFileType2[FilterFileType2["VUE_SFC"] = 0] = "VUE_SFC";
FilterFileType2[FilterFileType2["VUE_SFC_WITH_SETUP"] = 1] = "VUE_SFC_WITH_SETUP";
FilterFileType2[FilterFileType2["SETUP_SFC"] = 2] = "SETUP_SFC";
FilterFileType2[FilterFileType2["SRC_FILE"] = 3] = "SRC_FILE";
return FilterFileType2;
})(FilterFileType || {});
function getFilterPattern(types, framework) {
const filter = [];
const isWebpackLike = framework === "webpack" || framework === "rspack";
if (types.includes(0 /* VUE_SFC */)) {
filter.push(isWebpackLike ? REGEX_VUE_SUB : REGEX_VUE_SFC);
}
if (types.includes(1 /* VUE_SFC_WITH_SETUP */)) {
filter.push(isWebpackLike ? REGEX_VUE_SUB_SETUP : REGEX_VUE_SFC);
}
if (types.includes(2 /* SETUP_SFC */)) {
filter.push(REGEX_SETUP_SFC);
}
if (types.includes(3 /* SRC_FILE */)) {
filter.push(REGEX_SRC_FILE);
}
return filter;
}
function hackViteHMR(ctx, filter, callback) {
if (!filter(ctx.file)) return;
const { read } = ctx;
ctx.read = async () => {
const code = await read();
const result = await callback(code, ctx.file);
return result?.code || code;
};
}
// src/vue.ts
import {
parse
} from "@vue/compiler-sfc";
import { babelParse, getLang, resolveString } from "ast-kit";
function parseSFC(code, id) {
const sfc = parse(code, {
filename: id
});
const { descriptor, errors } = sfc;
const scriptLang = sfc.descriptor.script?.lang;
const scriptSetupLang = sfc.descriptor.scriptSetup?.lang;
if (sfc.descriptor.script && sfc.descriptor.scriptSetup && (scriptLang || "js") !== (scriptSetupLang || "js")) {
throw new Error(
`[vue-macros] <script> and <script setup> must have the same language type.`
);
}
const lang = scriptLang || scriptSetupLang;
return Object.assign({}, descriptor, {
sfc,
lang,
errors,
offset: descriptor.scriptSetup?.loc.start.offset ?? 0,
getSetupAst() {
if (!descriptor.scriptSetup) return;
return babelParse(descriptor.scriptSetup.content, lang, {
plugins: [["importAttributes", { deprecatedAssertSyntax: true }]],
cache: true
});
},
getScriptAst() {
if (!descriptor.script) return;
return babelParse(descriptor.script.content, lang, {
plugins: [["importAttributes", { deprecatedAssertSyntax: true }]],
cache: true
});
}
});
}
function getFileCodeAndLang(code, id) {
if (!REGEX_VUE_SFC.test(id)) {
return {
code,
lang: getLang(id)
};
}
const sfc = parseSFC(code, id);
const scriptCode = sfc.script?.content ?? "";
return {
code: sfc.scriptSetup ? `${scriptCode}
;
${sfc.scriptSetup.content}` : scriptCode,
lang: sfc.lang ?? "js"
};
}
function addNormalScript({ script, lang }, s) {
return {
start() {
if (script) return script.loc.end.offset;
const attrs = lang ? ` lang="${lang}"` : "";
s.prependLeft(0, `<script${attrs}>`);
return 0;
},
end() {
if (!script) s.appendRight(0, `
</script>
`);
}
};
}
function removeMacroImport(node, s, offset) {
if (node.type === "ImportDeclaration" && node.attributes?.some(
(attr) => resolveString(attr.key) === "type" && attr.value.value === "macro"
)) {
s.removeNode(node, { offset });
return true;
}
}
export {
DEFINE_EMIT,
DEFINE_EMITS,
DEFINE_MODELS,
DEFINE_MODELS_DOLLAR,
DEFINE_OPTIONS,
DEFINE_PROP,
DEFINE_PROPS,
DEFINE_PROPS_DOLLAR,
DEFINE_PROPS_REFS,
DEFINE_PROP_DOLLAR,
DEFINE_RENDER,
DEFINE_SETUP_COMPONENT,
DEFINE_SLOTS,
DEFINE_STYLEX,
FilterFileType,
HELPER_PREFIX,
REGEX_NODE_MODULES,
REGEX_SETUP_SFC,
REGEX_SETUP_SFC_SUB,
REGEX_SRC_FILE,
REGEX_SUPPORTED_EXT,
REGEX_VUE_SFC,
REGEX_VUE_SUB,
REGEX_VUE_SUB_SETUP,
REPO_ISSUE_URL,
TransformError,
VIRTUAL_ID_PREFIX,
WITH_DEFAULTS,
addNormalScript,
checkInvalidScopeReference,
createFilter,
createFilter2 as createRollupFilter,
detectVueVersion,
getFileCodeAndLang,
getFilterPattern,
getVuePluginApi,
hackViteHMR,
importHelperFn,
isStaticExpression,
isStaticObjectKey,
normalizePath,
parseSFC,
removeMacroImport,
resolveObjectExpression
};