2025/2/8第一次更新

This commit is contained in:
爱吃咸鱼小猫咪
2025-02-08 18:50:38 +08:00
commit d7af560866
26519 changed files with 5046029 additions and 0 deletions
@@ -0,0 +1,113 @@
import type { SFCDescriptor, SFCScriptBlock } from '@vue/compiler-sfc';
import type { ParserPlugin } from '@babel/parser';
import type { SFCTemplateCompileOptions } from '@vue/compiler-sfc';
export declare const normalScriptDefaultVar = "__default__";
export declare const DEFAULT_FILENAME = "anonymous.vue";
export interface SFCScriptCompileOptions {
root: string;
/**
* 类型
*/
componentType: 'app' | 'page' | 'component';
/**
* 是否同时支持使用 <script> 和 <script setup>
*/
scriptAndScriptSetup?: boolean;
/**
* Class name
*/
className: string;
/**
* Scope ID for prefixing injected CSS variables.
* This must be consistent with the `id` passed to `compileStyle`.
*/
id: string;
/**
* Production mode. Used to determine whether to generate hashed CSS variables
*/
isProd?: boolean;
/**
* Enable/disable source map. Defaults to true.
*/
sourceMap?: boolean;
/**
* https://babeljs.io/docs/en/babel-parser#plugins
*/
babelParserPlugins?: ParserPlugin[];
/**
* A list of files to parse for global types to be made available for type
* resolving in SFC macros. The list must be fully resolved file system paths.
*/
globalTypeFiles?: string[];
/**
* Compile the template and inline the resulting render function
* directly inside setup().
* - Only affects `<script setup>`
* - This should only be used in production because it prevents the template
* from being hot-reloaded separately from component state.
*/
inlineTemplate?: boolean;
/**
* Generate the final component as a variable instead of default export.
* This is useful in e.g. @vitejs/plugin-vue where the script needs to be
* placed inside the main module.
*/
genDefaultAs?: string;
/**
* Options for template compilation when inlining. Note these are options that
* would normally be passed to `compiler-sfc`'s own `compileTemplate()`, not
* options passed to `compiler-dom`.
*/
templateOptions?: Partial<SFCTemplateCompileOptions>;
/**
* Hoist <script setup> static constants.
* - Only enables when one `<script setup>` exists.
* @default true
*/
hoistStatic?: boolean;
/**
* (**Experimental**) Enable macro `defineModel`
* @default false
*/
defineModel?: boolean;
/**
* (**Experimental**) Enable reactive destructure for `defineProps`
* @default false
*/
propsDestructure?: boolean;
/**
* File system access methods to be used when resolving types
* imported in SFC macros. Defaults to ts.sys in Node.js, can be overwritten
* to use a virtual file system for use in browsers (e.g. in REPLs)
*/
fs?: {
fileExists(file: string): boolean;
readFile(file: string): string | undefined;
};
/**
* (Experimental) Enable syntax transform for using refs without `.value` and
* using destructured props with reactivity
* @deprecated the Reactivity Transform proposal has been dropped. This
* feature will be removed from Vue core in 3.4. If you intend to continue
* using it, disable this and switch to the [Vue Macros implementation](https://vue-macros.sxzz.moe/features/reactivity-transform.html).
*/
reactivityTransform?: boolean;
/**
* Transform Vue SFCs into custom elements.
*/
customElement?: boolean | ((filename: string) => boolean);
}
export interface ImportBinding {
isType: boolean;
imported: string;
local: string;
source: string;
isFromSetup: boolean;
isUsedInTemplate: boolean;
}
/**
* Compile `<script setup>`
* It requires the whole SFC descriptor because we need to handle and merge
* normal `<script>` + `<script setup>` if both are present.
*/
export declare function compileScript(sfc: SFCDescriptor, options: SFCScriptCompileOptions): SFCScriptBlock;
@@ -0,0 +1,989 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileScript = exports.DEFAULT_FILENAME = exports.normalScriptDefaultVar = void 0;
const compiler_dom_1 = require("@vue/compiler-dom");
const estree_walker_1 = require("estree-walker");
const source_map_js_1 = require("source-map-js");
const normalScript_1 = require("./script/normalScript");
const warn_1 = require("./warn");
const context_1 = require("./script/context");
const defineProps_1 = require("./script/defineProps");
const defineEmits_1 = require("./script/defineEmits");
const defineExpose_1 = require("./script/defineExpose");
const defineOptions_1 = require("./script/defineOptions");
const defineSlots_1 = require("./script/defineSlots");
const defineModel_1 = require("./script/defineModel");
const utils_1 = require("./script/utils");
const analyzeScriptBindings_1 = require("./script/analyzeScriptBindings");
const rewriteConsole_1 = require("./script/rewriteConsole");
const rewriteDebugError_1 = require("./script/rewriteDebugError");
const rewriteSourceMap_1 = require("./script/rewriteSourceMap");
exports.normalScriptDefaultVar = `__default__`;
exports.DEFAULT_FILENAME = 'anonymous.vue';
/**
* Compile `<script setup>`
* It requires the whole SFC descriptor because we need to handle and merge
* normal `<script>` + `<script setup>` if both are present.
*/
function compileScript(sfc, options) {
if (!options.id) {
(0, warn_1.warnOnce)(`compileScript now requires passing the \`id\` option.\n` +
`Upgrade your vite or vue-loader version for compatibility with ` +
`the latest experimental proposals.`);
}
const ctx = new context_1.ScriptCompileContext(sfc, options);
const { script, scriptSetup, source, filename } = sfc;
const hoistStatic = options.hoistStatic !== false && !script;
const scopeId = options.id ? options.id.replace(/^data-v-/, '') : '';
// 目前暂不提供<script setup>和<script>同时使用
// 目前给了个开关,用于单元测试
if (!options.scriptAndScriptSetup) {
if (script && scriptSetup) {
throw new Error(`<script setup> and <script> cannot be used together.`);
}
}
// TODO remove in 3.4
// const enableReactivityTransform = !!options.reactivityTransform
let refBindings;
if (!scriptSetup) {
if (!script) {
throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`);
}
// normal <script> only
return (0, normalScript_1.processNormalScript)(ctx, scopeId);
}
// if (script && scriptLang !== scriptSetupLang) {
// throw new Error(
// `[@vue/compiler-sfc] <script> and <script setup> must have the same ` +
// `language type.`
// )
// }
// if (scriptSetupLang && !ctx.isJS && !ctx.isTS) {
// // do not process non js/ts script blocks
// return scriptSetup
// }
// metadata that needs to be returned
// const ctx.bindingMetadata: BindingMetadata = {}
const scriptBindings = Object.create(null);
const setupBindings = Object.create(null);
let defaultExport;
let hasAwait = false;
// let hasInlinedSsrRenderFn = false
// string offsets
const startOffset = ctx.startOffset;
const endOffset = ctx.endOffset;
const scriptStartOffset = script && script.loc.start.offset;
const scriptEndOffset = script && script.loc.end.offset;
function hoistNode(node) {
const start = node.start + startOffset;
let end = node.end + startOffset;
// locate comment
if (node.trailingComments && node.trailingComments.length > 0) {
const lastCommentNode = node.trailingComments[node.trailingComments.length - 1];
end = lastCommentNode.end + startOffset;
}
// locate the end of whitespace between this statement and the next
while (end <= source.length) {
if (!/\s/.test(source.charAt(end))) {
break;
}
end++;
}
ctx.s.move(start, end, 0);
}
function registerUserImport(source, local, imported, isType, isFromSetup, needTemplateUsageCheck) {
ctx.userImports[local] = {
isType,
imported,
local,
source,
isFromSetup,
isUsedInTemplate: needTemplateUsageCheck,
};
}
function checkInvalidScopeReference(node, method) {
if (!node)
return;
(0, compiler_dom_1.walkIdentifiers)(node, (id) => {
const binding = setupBindings[id.name];
if (binding && binding !== compiler_dom_1.BindingTypes.LITERAL_CONST) {
ctx.error(`\`${method}()\` in <script setup> cannot reference locally ` +
`declared variables because it will be hoisted outside of the ` +
`setup() function. If your component options require initialization ` +
`in the module scope, use a separate normal <script> to export ` +
`the options instead.`, id);
}
});
}
const scriptAst = ctx.scriptAst;
const scriptSetupAst = ctx.scriptSetupAst;
const relativeFilename = ctx.descriptor.relativeFilename;
// 处理 console 的日志输出源码位置,不然就需要rust端读取 sourcemap 做映射
if (process.env.NODE_ENV === 'development' ||
process.env.UNI_RUST_TEST === 'true') {
if (scriptAst) {
// 仅 dev 处理
const scriptContent = ctx.descriptor.script.content;
const startLine = (ctx.descriptor.script.loc.start.line || 1) - 1;
const startOffset = ctx.descriptor.script.loc.start.offset || 0;
if ((0, rewriteDebugError_1.hasDebugError)(scriptContent)) {
(0, rewriteDebugError_1.rewriteDebugError)(scriptAst, ctx.s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
if (scriptContent.includes('console.')) {
(0, rewriteConsole_1.rewriteConsole)(scriptAst, ctx.s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
(0, rewriteSourceMap_1.rewriteSourceMap)(scriptAst, ctx.s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
if (scriptSetupAst) {
const scriptSetupContent = ctx.descriptor.scriptSetup.content;
const startLine = (ctx.descriptor.scriptSetup.loc.start.line || 1) - 1;
const startOffset = ctx.descriptor.scriptSetup.loc.start.offset || 0;
if ((0, rewriteDebugError_1.hasDebugError)(scriptSetupContent)) {
(0, rewriteDebugError_1.rewriteDebugError)(scriptSetupAst, ctx.s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
if ((0, rewriteConsole_1.hasConsole)(scriptSetupContent)) {
(0, rewriteConsole_1.rewriteConsole)(scriptSetupAst, ctx.s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
(0, rewriteSourceMap_1.rewriteSourceMap)(scriptSetupAst, ctx.s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
}
// 1.1 walk import declarations of <script>
if (scriptAst) {
for (const node of scriptAst.body) {
if (node.type === 'ImportDeclaration') {
// record imports for dedupe
for (const specifier of node.specifiers) {
const imported = (0, utils_1.getImportedName)(specifier);
registerUserImport(node.source.value, specifier.local.name, imported, node.importKind === 'type' ||
(specifier.type === 'ImportSpecifier' &&
specifier.importKind === 'type'), false, !options.inlineTemplate);
}
}
}
}
// 1.2 walk import declarations of <script setup>
for (const node of scriptSetupAst.body) {
if (node.type === 'ImportDeclaration') {
// import declarations are moved to top
hoistNode(node);
// dedupe imports
let removed = 0;
const removeSpecifier = (i) => {
const removeLeft = i > removed;
removed++;
const current = node.specifiers[i];
const next = node.specifiers[i + 1];
ctx.s.remove(removeLeft
? node.specifiers[i - 1].end + startOffset
: current.start + startOffset, next && !removeLeft
? next.start + startOffset
: current.end + startOffset);
};
for (let i = 0; i < node.specifiers.length; i++) {
const specifier = node.specifiers[i];
const local = specifier.local.name;
const imported = (0, utils_1.getImportedName)(specifier);
const source = node.source.value;
const existing = ctx.userImports[local];
if (source === 'vue' &&
(imported === defineProps_1.DEFINE_PROPS ||
imported === defineEmits_1.DEFINE_EMITS ||
imported === defineExpose_1.DEFINE_EXPOSE)) {
(0, warn_1.warnOnce)(`\`${imported}\` is a compiler macro and no longer needs to be imported.`);
removeSpecifier(i);
}
else if (existing) {
if (existing.source === source && existing.imported === imported) {
// already imported in <script setup>, dedupe
removeSpecifier(i);
}
else {
ctx.error(`different imports aliased to same local name.`, specifier);
}
}
else {
registerUserImport(source, local, imported, node.importKind === 'type' ||
(specifier.type === 'ImportSpecifier' &&
specifier.importKind === 'type'), true, !options.inlineTemplate);
}
}
if (node.specifiers.length && removed === node.specifiers.length) {
ctx.s.remove(node.start + startOffset, node.end + startOffset);
}
}
}
// 1.3 resolve possible user import alias of `ref` and `reactive`
const vueImportAliases = {};
for (const key in ctx.userImports) {
const { source, imported, local } = ctx.userImports[key];
if (source === 'vue')
vueImportAliases[imported] = local;
}
// 2.1 process normal <script> body
if (script && scriptAst) {
const scriptScope = {
offset: script.loc.start.offset,
filename: ctx.filename,
source: ctx.descriptor.source,
};
for (const node of scriptAst.body) {
if (node.type === 'ExportDefaultDeclaration') {
if (!options.scriptAndScriptSetup) {
ctx.error(`When <script> and <script setup> are used together, export default is not supported within <script>.`, node, scriptScope);
}
else {
// export default
defaultExport = node;
// check if user has manually specified `name` or 'render` option in
// export default
// if has name, skip name inference
// if has render and no template, generate return object instead of
// empty render function (#4980)
let optionProperties;
if (defaultExport.declaration.type === 'ObjectExpression') {
optionProperties = defaultExport.declaration.properties;
}
else if (defaultExport.declaration.type === 'CallExpression' &&
defaultExport.declaration.arguments[0] &&
defaultExport.declaration.arguments[0].type === 'ObjectExpression') {
optionProperties = defaultExport.declaration.arguments[0].properties;
}
if (optionProperties) {
for (const p of optionProperties) {
if (p.type === 'ObjectProperty' &&
p.key.type === 'Identifier' &&
p.key.name === 'name') {
ctx.hasDefaultExportName = true;
}
if ((p.type === 'ObjectMethod' || p.type === 'ObjectProperty') &&
p.key.type === 'Identifier' &&
p.key.name === 'render') {
// TODO warn when we provide a better way to do it?
ctx.hasDefaultExportRender = true;
}
}
}
// export default { ... } --> const __default__ = { ... }
const start = node.start + scriptStartOffset;
const end = node.declaration.start + scriptStartOffset;
ctx.s.overwrite(start, end, `const ${exports.normalScriptDefaultVar} = `);
}
}
else if (node.type === 'ExportNamedDeclaration') {
if (!options.scriptAndScriptSetup) {
ctx.error(`When <script> and <script setup> are used together, export is not supported within <script>.`, node, scriptScope);
}
else {
const defaultSpecifier = node.specifiers.find((s) => s.exported.type === 'Identifier' && s.exported.name === 'default');
if (defaultSpecifier) {
defaultExport = node;
// 1. remove specifier
if (node.specifiers.length > 1) {
ctx.s.remove(defaultSpecifier.start + scriptStartOffset, defaultSpecifier.end + scriptStartOffset);
}
else {
ctx.s.remove(node.start + scriptStartOffset, node.end + scriptStartOffset);
}
if (node.source) {
// export { x as default } from './x'
// rewrite to `import { x as __default__ } from './x'` and
// add to top
ctx.s.prepend(`import { ${defaultSpecifier.local.name} as ${exports.normalScriptDefaultVar} } from '${node.source.value}'\n`);
}
else {
// export { x as default }
// rewrite to `const __default__ = x` and move to end
ctx.s.appendLeft(scriptEndOffset, `\nconst ${exports.normalScriptDefaultVar} = ${defaultSpecifier.local.name}\n`);
}
}
if (node.declaration) {
walkDeclaration('script', node.declaration, scriptBindings, vueImportAliases, hoistStatic);
}
}
}
else if ((node.type === 'VariableDeclaration' ||
node.type === 'FunctionDeclaration' ||
node.type === 'ClassDeclaration' ||
node.type === 'TSEnumDeclaration') &&
!node.declare) {
walkDeclaration('script', node, scriptBindings, vueImportAliases, hoistStatic);
}
}
// apply reactivity transform
// TODO remove in 3.4
// if (enableReactivityTransform && shouldTransform(script.content)) {
// const { rootRefs, importedHelpers } = transformAST(
// scriptAst,
// ctx.s,
// scriptStartOffset!
// )
// refBindings = rootRefs
// for (const h of importedHelpers) {
// ctx.helperImports.add(h)
// }
// }
// <script> after <script setup>
// we need to move the block up so that `const __default__` is
// declared before being used in the actual component definition
if (scriptStartOffset > startOffset) {
// if content doesn't end with newline, add one
if (!/\n$/.test(script.content.trim())) {
ctx.s.appendLeft(scriptEndOffset, `\n`);
}
ctx.s.move(scriptStartOffset, scriptEndOffset, 0);
}
}
// 2.2 process <script setup> body
for (const node of scriptSetupAst.body) {
if (node.type === 'ExpressionStatement') {
const expr = (0, utils_1.unwrapTSNode)(node.expression);
// process `defineProps` and `defineEmit(s)` calls
if ((0, defineProps_1.processDefineProps)(ctx, expr) ||
(0, defineEmits_1.processDefineEmits)(ctx, expr) ||
(0, defineOptions_1.processDefineOptions)(ctx, expr) ||
(0, defineSlots_1.processDefineSlots)(ctx, expr)) {
ctx.s.remove(node.start + startOffset, node.end + startOffset);
}
else if ((0, defineExpose_1.processDefineExpose)(ctx, expr)) {
// defineExpose({}) -> expose({})
const callee = expr.callee;
ctx.s.overwrite(callee.start + startOffset, callee.end + startOffset, '__expose');
}
else {
(0, defineModel_1.processDefineModel)(ctx, expr);
}
}
if (node.type === 'VariableDeclaration' && !node.declare) {
const total = node.declarations.length;
let left = total;
let lastNonRemoved;
for (let i = 0; i < total; i++) {
const decl = node.declarations[i];
const init = decl.init && (0, utils_1.unwrapTSNode)(decl.init);
if (init) {
if ((0, defineOptions_1.processDefineOptions)(ctx, init)) {
ctx.error(`${defineOptions_1.DEFINE_OPTIONS}() has no returning value, it cannot be assigned.`, node);
}
// defineProps / defineEmits
const isDefineProps = (0, defineProps_1.processDefineProps)(ctx, init, decl.id);
const isDefineEmits = !isDefineProps && (0, defineEmits_1.processDefineEmits)(ctx, init, decl.id);
!isDefineEmits &&
((0, defineSlots_1.processDefineSlots)(ctx, init, decl.id) ||
(0, defineModel_1.processDefineModel)(ctx, init, decl.id));
if (isDefineProps &&
!ctx.propsDestructureRestId &&
ctx.propsDestructureDecl) {
if (left === 1) {
ctx.s.remove(node.start + startOffset, node.end + startOffset);
}
else {
let start = decl.start + startOffset;
let end = decl.end + startOffset;
if (i === total - 1) {
// last one, locate the end of the last one that is not removed
// if we arrive at this branch, there must have been a
// non-removed decl before us, so lastNonRemoved is non-null.
start = node.declarations[lastNonRemoved].end + startOffset;
}
else {
// not the last one, locate the start of the next
end = node.declarations[i + 1].start + startOffset;
}
ctx.s.remove(start, end);
left--;
}
}
else if (isDefineEmits) {
if (decl.id.type === 'Identifier') {
ctx.s.overwrite(startOffset + node.start, startOffset + node.end, `function ${decl.id.name}(event: string, ...do_not_transform_spread: Array<any | null>) {
__ins.emit(event, ...do_not_transform_spread)
}`);
}
// ctx.s.overwrite(
// startOffset + init.start!,
// startOffset + init.end!,
// '__emit'
// )
}
else {
lastNonRemoved = i;
}
}
}
}
let isAllLiteral = false;
// walk declarations to record declared bindings
if ((node.type === 'VariableDeclaration' ||
node.type === 'FunctionDeclaration' ||
node.type === 'ClassDeclaration' ||
node.type === 'TSEnumDeclaration') &&
!node.declare) {
isAllLiteral = walkDeclaration('scriptSetup', node, setupBindings, vueImportAliases, hoistStatic);
}
// hoist literal constants
if (hoistStatic && isAllLiteral) {
hoistNode(node);
}
// walk statements & named exports / variable declarations for top level
// await
if ((node.type === 'VariableDeclaration' && !node.declare) ||
node.type.endsWith('Statement')) {
const scope = [scriptSetupAst.body];
(0, estree_walker_1.walk)(node, {
enter(child, parent) {
if ((0, compiler_dom_1.isFunctionType)(child)) {
this.skip();
}
if (child.type === 'BlockStatement') {
scope.push(child.body);
}
if (child.type === 'AwaitExpression') {
ctx.error(`<script setup> cannot contain Top-level await.`, node);
// hasAwait = true
// // if the await expression is an expression statement and
// // - is in the root scope
// // - or is not the first statement in a nested block scope
// // then it needs a semicolon before the generated code.
// const currentScope = scope[scope.length - 1]
// const needsSemi = currentScope.some((n, i) => {
// return (
// (scope.length === 1 || i > 0) &&
// n.type === 'ExpressionStatement' &&
// n.start === child.start
// )
// })
// processAwait(
// ctx,
// child,
// needsSemi,
// parent!.type === 'ExpressionStatement'
// )
}
},
exit(node) {
if (node.type === 'BlockStatement')
scope.pop();
},
});
}
if ((node.type === 'ExportNamedDeclaration' && node.exportKind !== 'type') ||
node.type === 'ExportAllDeclaration' ||
node.type === 'ExportDefaultDeclaration') {
ctx.error(`<script setup> cannot contain ES module exports. ` +
`If you are using a previous version of <script setup>, please ` +
`consult the updated RFC at https://github.com/vuejs/rfcs/pull/227.`, node);
}
// move all Type declarations to outer scope
if (node.type.startsWith('TS') ||
(node.type === 'ExportNamedDeclaration' && node.exportKind === 'type') ||
(node.type === 'VariableDeclaration' && node.declare)) {
if (node.type !== 'TSEnumDeclaration') {
hoistNode(node);
}
}
}
// 3 props destructure transform
// if (ctx.propsDestructureDecl) {
// transformDestructuredProps(ctx, vueImportAliases)
// }
// 4. Apply reactivity transform
// TODO remove in 3.4
// if (
// enableReactivityTransform &&
// // normal <script> had ref bindings that maybe used in <script setup>
// (refBindings || shouldTransform(scriptSetup.content))
// ) {
// const { rootRefs, importedHelpers } = transformAST(
// scriptSetupAst,
// ctx.s,
// startOffset,
// refBindings
// )
// refBindings = refBindings ? [...refBindings, ...rootRefs] : rootRefs
// for (const h of importedHelpers) {
// ctx.helperImports.add(h)
// }
// }
// 5. check macro args to make sure it doesn't reference setup scope
// variables
checkInvalidScopeReference(ctx.propsRuntimeDecl, defineProps_1.DEFINE_PROPS);
checkInvalidScopeReference(ctx.propsRuntimeDefaults, defineProps_1.DEFINE_PROPS);
checkInvalidScopeReference(ctx.propsDestructureDecl, defineProps_1.DEFINE_PROPS);
checkInvalidScopeReference(ctx.emitsRuntimeDecl, defineEmits_1.DEFINE_EMITS);
checkInvalidScopeReference(ctx.optionsRuntimeDecl, defineOptions_1.DEFINE_OPTIONS);
// 6. remove non-script content
if (script) {
if (startOffset < scriptStartOffset) {
// <script setup> before <script>
ctx.s.remove(0, startOffset);
ctx.s.remove(endOffset, scriptStartOffset);
ctx.s.remove(scriptEndOffset, source.length);
}
else {
// <script> before <script setup>
ctx.s.remove(0, scriptStartOffset);
ctx.s.remove(scriptEndOffset, startOffset);
ctx.s.remove(endOffset, source.length);
}
}
else {
// only <script setup>
ctx.s.remove(0, startOffset);
ctx.s.remove(endOffset, source.length);
}
// 7. analyze binding metadata
// `defineProps` & `defineModel` also register props bindings
if (scriptAst) {
Object.assign(ctx.bindingMetadata, (0, analyzeScriptBindings_1.analyzeScriptBindings)(scriptAst.body));
}
for (const [key, { isType, imported, source }] of Object.entries(ctx.userImports)) {
if (isType)
continue;
ctx.bindingMetadata[key] =
imported === '*' ||
(imported === 'default' && source.endsWith('.vue')) ||
source === 'vue'
? compiler_dom_1.BindingTypes.SETUP_CONST
: compiler_dom_1.BindingTypes.SETUP_MAYBE_REF;
}
for (const key in scriptBindings) {
ctx.bindingMetadata[key] = scriptBindings[key];
}
for (const key in setupBindings) {
ctx.bindingMetadata[key] = setupBindings[key];
}
// known ref bindings
if (refBindings) {
for (const key of refBindings) {
ctx.bindingMetadata[key] = compiler_dom_1.BindingTypes.SETUP_REF;
}
}
// 8. inject `useCssVars` calls
// if (
// sfc.cssVars.length &&
// // no need to do this when targeting SSR
// !options.templateOptions?.ssr
// ) {
// ctx.helperImports.add(CSS_VARS_HELPER)
// ctx.helperImports.add('unref')
// ctx.s.prependLeft(
// startOffset,
// `\n${genCssVarsCode(
// sfc.cssVars,
// ctx.bindingMetadata,
// scopeId,
// !!options.isProd
// )}\n`
// )
// }
// 9. finalize setup() argument signature
let args = `__props`;
// inject user assignment of props
// we use a default __props so that template expressions referencing props
// can use it directly
if (ctx.propsDecl) {
if (ctx.propsDestructureRestId) {
ctx.s.overwrite(startOffset + ctx.propsCall.start, startOffset + ctx.propsCall.end, `${ctx.helper(`createPropsRestProxy`)}(__props, ${JSON.stringify(Object.keys(ctx.propsDestructuredBindings))})`);
ctx.s.overwrite(startOffset + ctx.propsDestructureDecl.start, startOffset + ctx.propsDestructureDecl.end, ctx.propsDestructureRestId);
}
else if (!ctx.propsDestructureDecl) {
ctx.s.overwrite(startOffset + ctx.propsCall.start, startOffset + ctx.propsCall.end, '__props');
}
}
// inject temp variables for async context preservation
// if (hasAwait) {
// const any = `: any`
// ctx.s.prependLeft(startOffset, `\nlet __temp${any}, __restore${any}\n`)
// }
const destructureElements = ctx.hasDefineExposeCall || !options.inlineTemplate
? [`expose: __expose`]
: [];
// emit 是个函数且不定参数,不通过解构处理
// if (ctx.emitDecl) {
// destructureElements.push(`emit: __emit`)
// }
if (destructureElements.length) {
args += `, { ${destructureElements.join(', ')} }: SetupContext`;
}
// 10. finalize default export
const genDefaultAs = options.genDefaultAs
? `const ${options.genDefaultAs} =`
: `export default`;
if (options.genDefaultAs) {
ctx.s.append(`\nexport default ${options.genDefaultAs}`);
}
let runtimeOptions = ``;
if (!ctx.hasDefaultExportName && filename && filename !== exports.DEFAULT_FILENAME) {
const match = filename.match(/([^/\\]+)\.\w+$/);
if (match) {
runtimeOptions += `\n __name: '${match[1]}',`;
}
}
// if (hasInlinedSsrRenderFn) {
// runtimeOptions += `\n __ssrInlineRender: true,`
// }
if (ctx.optionsRuntimeDecl) {
runtimeOptions +=
`\n` +
scriptSetup.content
.slice(ctx.optionsRuntimeDecl.start, ctx.optionsRuntimeDecl.end)
.trim()
.slice(1, -1) +
`,`;
}
const slotsDecl = (0, defineSlots_1.genRuntimeSlots)(ctx);
if (slotsDecl)
runtimeOptions += `\n slots: ${slotsDecl},`;
const propsDecl = (0, defineProps_1.genRuntimeProps)(ctx);
if (propsDecl) {
if (ctx.propsInterfaceDecl) {
runtimeOptions += `\n __props: ${ctx.propsInterfaceDecl.id.name},`;
}
runtimeOptions += `\n props: ${propsDecl},`;
}
const emitsDecl = (0, defineEmits_1.genRuntimeEmits)(ctx);
if (emitsDecl)
runtimeOptions += `\n emits: ${emitsDecl},`;
// <script setup> components are closed by default. If the user did not
// explicitly call `defineExpose`, call expose() with no args.
const exposeCall = ``;
// ctx.hasDefineExposeCall || options.inlineTemplate ? `` : ` __expose();\n`
// wrap setup code with function.
// for TS, make sure the exported type is still valid type with
// correct props information
// we have to use object spread for types to be merged properly
// user's TS setting should compile it down to proper targets
// export default defineComponent({ ...__default__, ... })
ctx.s.prependLeft(startOffset, `\n${genDefaultAs} ${ctx.helper((0, utils_1.resolveDefineCode)(ctx.options.componentType))}({${runtimeOptions}\n ` +
`${hasAwait ? `async ` : ``}setup(${args}): any | null {
const __ins = getCurrentInstance()!;
const _ctx = __ins.proxy${options.genDefaultAs
? ` as InstanceType<typeof ${options.genDefaultAs}>`
: ''};
const _cache = __ins.renderCache;
${exposeCall}`);
let scriptMap;
// 11. generate return statement
// 剩余由 rust 编译器处理
if (options.componentType !== 'app') {
const { code, preamble, map } = (0, normalScript_1.processTemplate)(sfc, {
relativeFilename,
bindingMetadata: ctx.bindingMetadata,
rootDir: options.root,
className: options.className,
});
if (preamble) {
ctx.s.prepend(preamble);
}
// 放到最后,以免查找 offset 有问题
let offset = map ? (ctx.s.toString().match(/\r?\n/g)?.length ?? 0) + 1 : 1;
if (options.genDefaultAs) {
offset = offset - 2; // 排除 export default __sfc__
}
ctx.s.appendRight(endOffset, `\nreturn ${code}\n}\n\n})`);
ctx.s.trim();
scriptMap =
options.sourceMap !== false
? ctx.s.generateMap({
source: relativeFilename,
hires: true,
includeContent: true,
})
: undefined;
if (map && scriptMap) {
scriptMap = generateScriptMap(offset, map, scriptMap);
}
}
else {
ctx.s.appendRight(endOffset, `})`);
ctx.s.trim();
scriptMap =
options.sourceMap !== false
? ctx.s.generateMap({
source: relativeFilename,
hires: true,
includeContent: true,
})
: undefined;
}
// 12. finalize Vue helper imports
// if (ctx.helperImports.size > 0) {
// ctx.s.prepend(
// `import { ${[...ctx.helperImports]
// .map((h) => `${h} as _${h}`)
// .join(', ')} } from 'vue'\n`
// )
// }
return {
...scriptSetup,
bindings: ctx.bindingMetadata,
imports: ctx.userImports,
content: ctx.s.toString(),
map: scriptMap,
scriptAst: scriptAst?.body,
scriptSetupAst: scriptSetupAst?.body,
deps: ctx.deps ? [...ctx.deps] : undefined,
};
}
exports.compileScript = compileScript;
function generateScriptMap(offset, templateMap, scriptMap) {
const templateMapConsumer = new source_map_js_1.SourceMapConsumer(templateMap);
const scriptMapConsumer = new source_map_js_1.SourceMapConsumer(scriptMap);
const scriptMapGenerator = new source_map_js_1.SourceMapGenerator();
scriptMapConsumer.eachMapping((m) => {
scriptMapGenerator.addMapping({
original: {
line: m.originalLine ?? 0,
column: m.originalColumn ?? 0,
},
generated: {
line: m.generatedLine,
column: m.generatedColumn,
},
source: m.source,
name: m.name,
});
});
templateMapConsumer.eachMapping((m) => {
scriptMapGenerator.addMapping({
original: {
line: m.originalLine ?? 0,
column: m.originalColumn ?? 0,
},
generated: {
line: m.generatedLine + offset,
column: m.generatedColumn,
},
source: m.source,
name: m.name,
});
});
scriptMap.sources.forEach(function (sourceFile) {
const sourceContent = scriptMapConsumer.sourceContentFor(sourceFile);
if (sourceContent != null) {
scriptMapGenerator.setSourceContent(sourceFile, sourceContent);
}
});
return JSON.parse(scriptMapGenerator.toString());
}
function registerBinding(bindings, node, type) {
bindings[node.name] = type;
}
function walkDeclaration(from, node, bindings, userImportAliases, hoistStatic) {
let isAllLiteral = false;
if (node.type === 'VariableDeclaration') {
const isConst = node.kind === 'const';
isAllLiteral =
isConst &&
node.declarations.every((decl) => decl.id.type === 'Identifier' && isStaticNode(decl.init));
// export const foo = ...
for (const { id, init: _init } of node.declarations) {
const init = _init && (0, utils_1.unwrapTSNode)(_init);
const isDefineCall = !!(isConst &&
(0, utils_1.isCallOf)(init, (c) => c === defineProps_1.DEFINE_PROPS || c === defineEmits_1.DEFINE_EMITS || c === defineProps_1.WITH_DEFAULTS));
if (id.type === 'Identifier') {
let bindingType;
const userReactiveBinding = userImportAliases['reactive'];
if ((hoistStatic || from === 'script') &&
(isAllLiteral || (isConst && isStaticNode(init)))) {
bindingType = compiler_dom_1.BindingTypes.LITERAL_CONST;
}
else if ((0, utils_1.isCallOf)(init, userReactiveBinding)) {
// treat reactive() calls as let since it's meant to be mutable
bindingType = isConst
? compiler_dom_1.BindingTypes.SETUP_REACTIVE_CONST
: compiler_dom_1.BindingTypes.SETUP_LET;
}
else if (
// if a declaration is a const literal, we can mark it so that
// the generated render fn code doesn't need to unref() it
isDefineCall ||
(isConst && canNeverBeRef(init, userReactiveBinding))) {
bindingType = (0, utils_1.isCallOf)(init, defineProps_1.DEFINE_PROPS)
? compiler_dom_1.BindingTypes.SETUP_REACTIVE_CONST
: compiler_dom_1.BindingTypes.SETUP_CONST;
}
else if (isConst) {
if ((0, utils_1.isCallOf)(init, (m) => m === userImportAliases['ref'] ||
m === userImportAliases['computed'] ||
m === userImportAliases['shallowRef'] ||
m === userImportAliases['customRef'] ||
m === userImportAliases['toRef'] ||
m === defineModel_1.DEFINE_MODEL)) {
bindingType = compiler_dom_1.BindingTypes.SETUP_REF;
}
else {
bindingType = compiler_dom_1.BindingTypes.SETUP_MAYBE_REF;
}
}
else {
bindingType = compiler_dom_1.BindingTypes.SETUP_LET;
}
registerBinding(bindings, id, bindingType);
}
else {
if ((0, utils_1.isCallOf)(init, defineProps_1.DEFINE_PROPS)) {
continue;
}
if (id.type === 'ObjectPattern') {
walkObjectPattern(id, bindings, isConst, isDefineCall);
}
else if (id.type === 'ArrayPattern') {
walkArrayPattern(id, bindings, isConst, isDefineCall);
}
}
}
}
else if (node.type === 'TSEnumDeclaration') {
isAllLiteral = node.members.every((member) => !member.initializer || isStaticNode(member.initializer));
bindings[node.id.name] = isAllLiteral
? compiler_dom_1.BindingTypes.LITERAL_CONST
: compiler_dom_1.BindingTypes.SETUP_CONST;
}
else if (node.type === 'FunctionDeclaration' ||
node.type === 'ClassDeclaration') {
// export function foo() {} / export class Foo {}
// export declarations must be named.
bindings[node.id.name] = compiler_dom_1.BindingTypes.SETUP_CONST;
}
return isAllLiteral;
}
function walkObjectPattern(node, bindings, isConst, isDefineCall = false) {
for (const p of node.properties) {
if (p.type === 'ObjectProperty') {
if (p.key.type === 'Identifier' && p.key === p.value) {
// shorthand: const { x } = ...
const type = isDefineCall
? compiler_dom_1.BindingTypes.SETUP_CONST
: isConst
? compiler_dom_1.BindingTypes.SETUP_MAYBE_REF
: compiler_dom_1.BindingTypes.SETUP_LET;
registerBinding(bindings, p.key, type);
}
else {
walkPattern(p.value, bindings, isConst, isDefineCall);
}
}
else {
// ...rest
// argument can only be identifier when destructuring
const type = isConst ? compiler_dom_1.BindingTypes.SETUP_CONST : compiler_dom_1.BindingTypes.SETUP_LET;
registerBinding(bindings, p.argument, type);
}
}
}
function walkArrayPattern(node, bindings, isConst, isDefineCall = false) {
for (const e of node.elements) {
e && walkPattern(e, bindings, isConst, isDefineCall);
}
}
function walkPattern(node, bindings, isConst, isDefineCall = false) {
if (node.type === 'Identifier') {
const type = isDefineCall
? compiler_dom_1.BindingTypes.SETUP_CONST
: isConst
? compiler_dom_1.BindingTypes.SETUP_MAYBE_REF
: compiler_dom_1.BindingTypes.SETUP_LET;
registerBinding(bindings, node, type);
}
else if (node.type === 'RestElement') {
// argument can only be identifier when destructuring
const type = isConst ? compiler_dom_1.BindingTypes.SETUP_CONST : compiler_dom_1.BindingTypes.SETUP_LET;
registerBinding(bindings, node.argument, type);
}
else if (node.type === 'ObjectPattern') {
walkObjectPattern(node, bindings, isConst);
}
else if (node.type === 'ArrayPattern') {
walkArrayPattern(node, bindings, isConst);
}
else if (node.type === 'AssignmentPattern') {
if (node.left.type === 'Identifier') {
const type = isDefineCall
? compiler_dom_1.BindingTypes.SETUP_CONST
: isConst
? compiler_dom_1.BindingTypes.SETUP_MAYBE_REF
: compiler_dom_1.BindingTypes.SETUP_LET;
registerBinding(bindings, node.left, type);
}
else {
walkPattern(node.left, bindings, isConst);
}
}
}
function canNeverBeRef(node, userReactiveImport) {
if ((0, utils_1.isCallOf)(node, userReactiveImport)) {
return true;
}
switch (node.type) {
case 'UnaryExpression':
case 'BinaryExpression':
case 'ArrayExpression':
case 'ObjectExpression':
case 'FunctionExpression':
case 'ArrowFunctionExpression':
case 'UpdateExpression':
case 'ClassExpression':
case 'TaggedTemplateExpression':
return true;
case 'SequenceExpression':
return canNeverBeRef(node.expressions[node.expressions.length - 1], userReactiveImport);
default:
if ((0, utils_1.isLiteralNode)(node)) {
return true;
}
return false;
}
}
function isStaticNode(node) {
node = (0, utils_1.unwrapTSNode)(node);
switch (node.type) {
case 'UnaryExpression': // void 0, !true
return isStaticNode(node.argument);
case 'LogicalExpression': // 1 > 2
case 'BinaryExpression': // 1 + 2
return isStaticNode(node.left) && isStaticNode(node.right);
case 'ConditionalExpression': {
// 1 ? 2 : 3
return (isStaticNode(node.test) &&
isStaticNode(node.consequent) &&
isStaticNode(node.alternate));
}
case 'SequenceExpression': // (1, 2)
case 'TemplateLiteral': // `foo${1}`
return node.expressions.every((expr) => isStaticNode(expr));
case 'ParenthesizedExpression': // (1)
return isStaticNode(node.expression);
case 'StringLiteral':
case 'NumericLiteral':
case 'BooleanLiteral':
case 'NullLiteral':
case 'BigIntLiteral':
return true;
}
return false;
}
@@ -0,0 +1,10 @@
import MagicString from 'magic-string';
import type { ParserPlugin } from '@babel/parser';
import type { Statement } from '@babel/types';
export declare function rewriteDefault(input: string, as: string, define: string, parserPlugins?: ParserPlugin[]): string;
/**
* Utility for rewriting `export default` in a script block into a variable
* declaration so that we can inject things into it
*/
export declare function rewriteDefaultAST(ast: Statement[], s: MagicString, as: string, define: string): void;
export declare function hasDefaultExport(ast: Statement[]): boolean;
@@ -0,0 +1,105 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasDefaultExport = exports.rewriteDefaultAST = exports.rewriteDefault = void 0;
const parser_1 = require("@babel/parser");
const magic_string_1 = __importDefault(require("magic-string"));
function rewriteDefault(input, as, define, parserPlugins) {
const ast = (0, parser_1.parse)(input, {
sourceType: 'module',
plugins: parserPlugins,
}).program.body;
const s = new magic_string_1.default(input);
rewriteDefaultAST(ast, s, as, define);
return s.toString();
}
exports.rewriteDefault = rewriteDefault;
/**
* Utility for rewriting `export default` in a script block into a variable
* declaration so that we can inject things into it
*/
function rewriteDefaultAST(ast, s, as, define) {
if (!hasDefaultExport(ast)) {
s.append(`\nconst ${as} = ${define}({})`);
return;
}
// if the script somehow still contains `default export`, it probably has
// multi-line comments or template strings. fallback to a full parse.
ast.forEach((node) => {
if (node.type === 'ExportDefaultDeclaration') {
if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) {
let start = node.declaration.decorators && node.declaration.decorators.length > 0
? node.declaration.decorators[node.declaration.decorators.length - 1].end
: node.start;
s.overwrite(start, node.declaration.id.start, ` class `);
s.append(`\nconst ${as} = ${define}(${node.declaration.id.name})`);
}
else {
s.overwrite(node.start, node.declaration.start, `const ${as} = ${define}(`);
s.appendRight(node.declaration.end, ')');
}
}
else if (node.type === 'ExportNamedDeclaration') {
for (const specifier of node.specifiers) {
if (specifier.type === 'ExportSpecifier' &&
specifier.exported.type === 'Identifier' &&
specifier.exported.name === 'default') {
if (node.source) {
if (specifier.local.name === 'default') {
s.prepend(`import { default as __VUE_DEFAULT__ } from '${node.source.value}'\n`);
const end = specifierEnd(s, specifier.local.end, node.end);
s.remove(specifier.start, end);
s.append(`\nconst ${as} = ${define}(__VUE_DEFAULT___)`);
continue;
}
else {
s.prepend(`import { ${s.slice(specifier.local.start, specifier.local.end)} as __VUE_DEFAULT__ } from '${node.source.value}'\n`);
const end = specifierEnd(s, specifier.exported.end, node.end);
s.remove(specifier.start, end);
s.append(`\nconst ${as} = ${define}(__VUE_DEFAULT__)`);
continue;
}
}
const end = specifierEnd(s, specifier.end, node.end);
s.remove(specifier.start, end);
s.append(`\nconst ${as} = ${specifier.local.name}`);
}
}
}
});
}
exports.rewriteDefaultAST = rewriteDefaultAST;
function hasDefaultExport(ast) {
for (const stmt of ast) {
if (stmt.type === 'ExportDefaultDeclaration') {
return true;
}
else if (stmt.type === 'ExportNamedDeclaration' &&
stmt.specifiers.some((spec) => spec.exported.name === 'default')) {
return true;
}
}
return false;
}
exports.hasDefaultExport = hasDefaultExport;
function specifierEnd(s, end, nodeEnd) {
// export { default , foo } ...
let hasCommas = false;
let oldEnd = end;
while (end < nodeEnd) {
if (/\s/.test(s.slice(end, end + 1))) {
end++;
}
else if (s.slice(end, end + 1) === ',') {
end++;
hasCommas = true;
break;
}
else if (s.slice(end, end + 1) === '}') {
break;
}
}
return hasCommas ? end : oldEnd;
}
@@ -0,0 +1,9 @@
import type { Node, Statement } from '@babel/types';
import { type BindingMetadata } from '@vue/compiler-dom';
/**
* Analyze bindings in normal `<script>`
* Note that `compileScriptSetup` already analyzes bindings as part of its
* compilation process so this should only be used on single `<script>` SFCs.
*/
export declare function analyzeScriptBindings(ast: Statement[]): BindingMetadata;
export declare function getObjectOrArrayExpressionKeys(value: Node): string[];
@@ -0,0 +1,113 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getObjectOrArrayExpressionKeys = exports.analyzeScriptBindings = void 0;
const compiler_dom_1 = require("@vue/compiler-dom");
const utils_1 = require("./utils");
/**
* Analyze bindings in normal `<script>`
* Note that `compileScriptSetup` already analyzes bindings as part of its
* compilation process so this should only be used on single `<script>` SFCs.
*/
function analyzeScriptBindings(ast) {
for (const node of ast) {
if (node.type === 'ExportDefaultDeclaration' &&
node.declaration.type === 'ObjectExpression') {
return analyzeBindingsFromOptions(node.declaration);
}
}
return {};
}
exports.analyzeScriptBindings = analyzeScriptBindings;
function analyzeBindingsFromOptions(node) {
const bindings = {};
// #3270, #3275
// mark non-script-setup so we don't resolve components/directives from these
Object.defineProperty(bindings, '__isScriptSetup', {
enumerable: false,
value: false,
});
for (const property of node.properties) {
if (property.type === 'ObjectProperty' &&
!property.computed &&
property.key.type === 'Identifier') {
// props
if (property.key.name === 'props') {
// props: ['foo']
// props: { foo: ... }
for (const key of getObjectOrArrayExpressionKeys(property.value)) {
bindings[key] = compiler_dom_1.BindingTypes.PROPS;
}
}
// inject
else if (property.key.name === 'inject') {
// inject: ['foo']
// inject: { foo: {} }
for (const key of getObjectOrArrayExpressionKeys(property.value)) {
bindings[key] = compiler_dom_1.BindingTypes.OPTIONS;
}
}
// computed & methods
else if (property.value.type === 'ObjectExpression' &&
(property.key.name === 'computed' || property.key.name === 'methods')) {
// methods: { foo() {} }
// computed: { foo() {} }
for (const key of getObjectExpressionKeys(property.value)) {
bindings[key] = compiler_dom_1.BindingTypes.OPTIONS;
}
}
}
// setup & data
else if (property.type === 'ObjectMethod' &&
property.key.type === 'Identifier' &&
(property.key.name === 'setup' || property.key.name === 'data')) {
for (const bodyItem of property.body.body) {
// setup() {
// return {
// foo: null
// }
// }
if (bodyItem.type === 'ReturnStatement' &&
bodyItem.argument &&
bodyItem.argument.type === 'ObjectExpression') {
for (const key of getObjectExpressionKeys(bodyItem.argument)) {
bindings[key] =
property.key.name === 'setup'
? compiler_dom_1.BindingTypes.SETUP_MAYBE_REF
: compiler_dom_1.BindingTypes.DATA;
}
}
}
}
}
return bindings;
}
function getObjectExpressionKeys(node) {
const keys = [];
for (const prop of node.properties) {
if (prop.type === 'SpreadElement')
continue;
const key = (0, utils_1.resolveObjectKey)(prop.key, prop.computed);
if (key)
keys.push(String(key));
}
return keys;
}
function getArrayExpressionKeys(node) {
const keys = [];
for (const element of node.elements) {
if (element && element.type === 'StringLiteral') {
keys.push(element.value);
}
}
return keys;
}
function getObjectOrArrayExpressionKeys(value) {
if (value.type === 'ArrayExpression') {
return getArrayExpressionKeys(value);
}
if (value.type === 'ObjectExpression') {
return getObjectExpressionKeys(value);
}
return [];
}
exports.getObjectOrArrayExpressionKeys = getObjectOrArrayExpressionKeys;
@@ -0,0 +1,61 @@
import type { CallExpression, Node, ObjectPattern, Program, TSInterfaceDeclaration, TSTypeLiteral } from '@babel/types';
import type { SFCDescriptor } from '@vue/compiler-sfc';
import { type ParserPlugin } from '@babel/parser';
import type { ImportBinding, SFCScriptCompileOptions } from '../compileScript';
import type { PropsDestructureBindings } from './defineProps';
import type { ModelDecl } from './defineModel';
import type { BindingMetadata } from '@vue/compiler-core';
import MagicString from 'magic-string';
import type { TypeScope } from './resolveType';
export declare class ScriptCompileContext {
descriptor: SFCDescriptor;
options: Partial<SFCScriptCompileOptions>;
scriptAst: Program | null;
scriptSetupAst: Program | null;
source: string;
filename: string;
s: MagicString;
startOffset: number | undefined;
endOffset: number | undefined;
scope?: TypeScope;
globalScopes?: TypeScope[];
userImports: Record<string, ImportBinding>;
hasDefinePropsCall: boolean;
hasDefineEmitCall: boolean;
hasDefineExposeCall: boolean;
hasDefaultExportName: boolean;
hasDefaultExportRender: boolean;
hasDefineOptionsCall: boolean;
hasDefineSlotsCall: boolean;
hasDefineModelCall: boolean;
propsCall: CallExpression | undefined;
propsDecl: Node | undefined;
propsRuntimeDecl: Node | undefined;
propsTypeDecl: Node | undefined;
propsDestructureDecl: ObjectPattern | undefined;
propsDestructuredBindings: PropsDestructureBindings;
propsDestructureRestId: string | undefined;
propsRuntimeDefaults: Node | undefined;
propsInterfaceDecl: TSInterfaceDeclaration | undefined;
emitsRuntimeDecl: Node | undefined;
emitsTypeDecl: Node | undefined;
emitDecl: Node | undefined;
modelDecls: Record<string, ModelDecl>;
optionsRuntimeDecl: Node | undefined;
slotsRuntimeDecl: TSTypeLiteral | undefined;
bindingMetadata: BindingMetadata;
helperImports: Set<string>;
helper(key: string): string;
/**
* to be exposed on compiled script block for HMR cache busting
*/
deps?: Set<string>;
/**
* cache for resolved fs
*/
fs?: NonNullable<SFCScriptCompileOptions['fs']>;
constructor(descriptor: SFCDescriptor, options: Partial<SFCScriptCompileOptions>);
getString(node: Node, scriptSetup?: boolean): string;
error(msg: string, node: Node, scope?: TypeScope): never;
}
export declare function resolveParserPlugins(lang: string, userPlugins?: ParserPlugin[], dts?: boolean): (import("@babel/parser").ParserPluginWithOptions | ("asyncDoExpressions" | "asyncGenerators" | "bigInt" | "classPrivateMethods" | "classPrivateProperties" | "classProperties" | "classStaticBlock" | "decimal" | "decorators-legacy" | "deferredImportEvaluation" | "decoratorAutoAccessors" | "destructuringPrivate" | "doExpressions" | "dynamicImport" | "explicitResourceManagement" | "exportDefaultFrom" | "exportNamespaceFrom" | "flow" | "flowComments" | "functionBind" | "functionSent" | "importMeta" | "jsx" | "logicalAssignment" | "importAssertions" | "importAttributes" | "importReflection" | "moduleBlocks" | "moduleStringNames" | "nullishCoalescingOperator" | "numericSeparator" | "objectRestSpread" | "optionalCatchBinding" | "optionalChaining" | "partialApplication" | "placeholders" | "privateIn" | "regexpUnicodeSets" | "sourcePhaseImports" | "throwExpressions" | "topLevelAwait" | "v8intrinsic" | "decorators" | "estree" | "moduleAttributes" | "optionalChainingAssign" | "pipelineOperator" | "recordAndTuple" | "typescript"))[];
@@ -0,0 +1,105 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveParserPlugins = exports.ScriptCompileContext = void 0;
const shared_1 = require("@vue/shared");
const parser_1 = require("@babel/parser");
const magic_string_1 = __importDefault(require("magic-string"));
class ScriptCompileContext {
helper(key) {
this.helperImports.add(key);
return `${key}`;
}
constructor(descriptor, options) {
this.descriptor = descriptor;
this.options = options;
this.source = this.descriptor.source;
this.filename = this.descriptor.filename;
this.s = new magic_string_1.default(this.source);
this.startOffset = this.descriptor.scriptSetup?.loc.start.offset;
this.endOffset = this.descriptor.scriptSetup?.loc.end.offset;
this.userImports = Object.create(null);
// macros presence check
this.hasDefinePropsCall = false;
this.hasDefineEmitCall = false;
this.hasDefineExposeCall = false;
this.hasDefaultExportName = false;
this.hasDefaultExportRender = false;
this.hasDefineOptionsCall = false;
this.hasDefineSlotsCall = false;
this.hasDefineModelCall = false;
this.propsDestructuredBindings = Object.create(null);
// defineModel
this.modelDecls = Object.create(null);
// codegen
this.bindingMetadata = {};
this.helperImports = new Set();
// resolve parser plugins
const plugins = resolveParserPlugins('ts', options.babelParserPlugins);
function parse(input, offset, startLine) {
try {
return (0, parser_1.parse)(input, {
plugins,
sourceType: 'module',
// 阻止语法解析报错,不影响后续的语法解析,比如
// This member cannot have an 'override' modifier because its containing class does not extend another class.
errorRecovery: true,
}).program;
}
catch (e) {
if (e.loc && startLine) {
e.loc.line = e.loc.line + (startLine - 1);
}
e.message = `[vue/compiler-sfc] ${e.message}\n\n${descriptor.filename}\n${(0, shared_1.generateCodeFrame)(descriptor.source, e.pos + offset, e.pos + offset + 1)}`;
throw e;
}
}
this.scriptAst =
descriptor.script &&
parse(descriptor.script.content, descriptor.script.loc.start.offset, descriptor.script.loc.start.line);
this.scriptSetupAst =
descriptor.scriptSetup &&
parse(descriptor.scriptSetup.content, this.startOffset, descriptor.scriptSetup.loc.start.line);
}
getString(node, scriptSetup = true) {
const block = scriptSetup
? this.descriptor.scriptSetup
: this.descriptor.script;
return block.content.slice(node.start, node.end);
}
error(msg, node, scope) {
const offset = scope ? scope.offset : this.startOffset;
throw new Error(`[@vue/compiler-sfc] ${msg}\n\n${(scope || this.descriptor).filename}\n${(0, shared_1.generateCodeFrame)((scope || this.descriptor).source, node.start + offset, node.end + offset)}`);
}
}
exports.ScriptCompileContext = ScriptCompileContext;
function resolveParserPlugins(lang, userPlugins, dts = false) {
const plugins = [];
if (!userPlugins ||
!userPlugins.some((p) => p === 'importAssertions' ||
p === 'importAttributes' ||
((0, shared_1.isArray)(p) && p[0] === 'importAttributes'))) {
plugins.push('importAttributes');
}
if (lang === 'jsx' || lang === 'tsx') {
plugins.push('jsx');
}
else if (userPlugins) {
// If don't match the case of adding jsx
// should remove the jsx from user options
userPlugins = userPlugins.filter((p) => p !== 'jsx');
}
if (lang === 'ts' || lang === 'tsx') {
plugins.push(['typescript', { dts }], 'explicitResourceManagement');
if (!userPlugins || !userPlugins.includes('decorators')) {
plugins.push('decorators-legacy');
}
}
if (userPlugins) {
plugins.push(...userPlugins);
}
return plugins;
}
exports.resolveParserPlugins = resolveParserPlugins;
@@ -0,0 +1,5 @@
import type { LVal, Node } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare const DEFINE_EMITS = "defineEmits";
export declare function processDefineEmits(ctx: ScriptCompileContext, node: Node, declId?: LVal): boolean;
export declare function genRuntimeEmits(ctx: ScriptCompileContext): string | undefined;
@@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genRuntimeEmits = exports.processDefineEmits = exports.DEFINE_EMITS = void 0;
const utils_1 = require("./utils");
const resolveType_1 = require("./resolveType");
exports.DEFINE_EMITS = 'defineEmits';
function processDefineEmits(ctx, node, declId) {
if (!(0, utils_1.isCallOf)(node, exports.DEFINE_EMITS)) {
return false;
}
if (ctx.hasDefineEmitCall) {
ctx.error(`duplicate ${exports.DEFINE_EMITS}() call`, node);
}
ctx.hasDefineEmitCall = true;
ctx.emitsRuntimeDecl = node.arguments[0];
if (node.typeParameters) {
if (ctx.emitsRuntimeDecl) {
ctx.error(`${exports.DEFINE_EMITS}() cannot accept both type and non-type arguments ` +
`at the same time. Use one or the other.`, node);
}
ctx.emitsTypeDecl = node.typeParameters.params[0];
}
ctx.emitDecl = declId;
return true;
}
exports.processDefineEmits = processDefineEmits;
function genRuntimeEmits(ctx) {
let emitsDecl = '';
if (ctx.emitsRuntimeDecl) {
emitsDecl = ctx.getString(ctx.emitsRuntimeDecl).trim();
}
else if (ctx.emitsTypeDecl) {
const typeDeclaredEmits = extractRuntimeEmits(ctx);
emitsDecl = typeDeclaredEmits.size
? `[${Array.from(typeDeclaredEmits)
.map((k) => JSON.stringify(k))
.join(', ')}]`
: ``;
}
if (ctx.hasDefineModelCall) {
let modelEmitsDecl = `[${Object.keys(ctx.modelDecls)
.map((n) => JSON.stringify(`update:${n}`))
.join(', ')}]`;
emitsDecl = emitsDecl
? `/*#__PURE__*/${ctx.helper('mergeModels')}(${emitsDecl}, ${modelEmitsDecl})`
: modelEmitsDecl;
}
return emitsDecl;
}
exports.genRuntimeEmits = genRuntimeEmits;
function extractRuntimeEmits(ctx) {
const emits = new Set();
const node = ctx.emitsTypeDecl;
if (node.type === 'TSFunctionType') {
extractEventNames(ctx, node.parameters[0], emits);
return emits;
}
const { props, calls } = (0, resolveType_1.resolveTypeElements)(ctx, node);
let hasProperty = false;
for (const key in props) {
emits.add(key);
hasProperty = true;
}
if (calls) {
if (hasProperty) {
ctx.error(`defineEmits() type cannot mixed call signature and property syntax.`, node);
}
for (const call of calls) {
extractEventNames(ctx, call.parameters[0], emits);
}
}
return emits;
}
function extractEventNames(ctx, eventName, emits) {
if (eventName.type === 'Identifier' &&
eventName.typeAnnotation &&
eventName.typeAnnotation.type === 'TSTypeAnnotation') {
const types = (0, resolveType_1.resolveUnionType)(ctx, eventName.typeAnnotation.typeAnnotation);
for (const type of types) {
if (type.type === 'TSLiteralType') {
if (type.literal.type !== 'UnaryExpression' &&
type.literal.type !== 'TemplateLiteral') {
emits.add(String(type.literal.value));
}
}
}
}
}
@@ -0,0 +1,4 @@
import type { Node } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare const DEFINE_EXPOSE = "defineExpose";
export declare function processDefineExpose(ctx: ScriptCompileContext, node: Node): boolean;
@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processDefineExpose = exports.DEFINE_EXPOSE = void 0;
const utils_1 = require("./utils");
exports.DEFINE_EXPOSE = 'defineExpose';
function processDefineExpose(ctx, node) {
if ((0, utils_1.isCallOf)(node, exports.DEFINE_EXPOSE)) {
if (ctx.hasDefineExposeCall) {
ctx.error(`duplicate ${exports.DEFINE_EXPOSE}() call`, node);
}
ctx.hasDefineExposeCall = true;
return true;
}
return false;
}
exports.processDefineExpose = processDefineExpose;
@@ -0,0 +1,10 @@
import type { LVal, Node, TSType } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare const DEFINE_MODEL = "defineModel";
export interface ModelDecl {
type: TSType | undefined;
options: string | undefined;
identifier: string | undefined;
}
export declare function processDefineModel(ctx: ScriptCompileContext, node: Node, declId?: LVal): boolean;
export declare function genModelProps(ctx: ScriptCompileContext): string | undefined;
@@ -0,0 +1,147 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genModelProps = exports.processDefineModel = exports.DEFINE_MODEL = void 0;
const resolveType_1 = require("./resolveType");
const utils_1 = require("./utils");
const compiler_dom_1 = require("@vue/compiler-dom");
// import { warnOnce } from '../warn'
exports.DEFINE_MODEL = 'defineModel';
const RUNTIME_TYPES = {
Boolean: 'boolean',
String: 'string',
Number: 'number',
};
function processDefineModel(ctx, node, declId) {
if (!(0, utils_1.isCallOf)(node, exports.DEFINE_MODEL)) {
return false;
}
// if (!ctx.options.defineModel) {
// warnOnce(
// `defineModel() is an experimental feature and disabled by default.\n` +
// `To enable it, follow the RFC at https://github.com/vuejs/rfcs/discussions/503.`
// )
// return false
// }
// warnOnce(
// `This project is using defineModel(), which is an experimental ` +
// `feature. It may receive breaking changes or be removed in the future, so ` +
// `use at your own risk.\n` +
// `To stay updated, follow the RFC at https://github.com/vuejs/rfcs/discussions/503.`
// )
ctx.hasDefineModelCall = true;
const type = (node.typeParameters && node.typeParameters.params[0]) || undefined;
let modelName;
let options;
const arg0 = node.arguments[0] && (0, utils_1.unwrapTSNode)(node.arguments[0]);
if (arg0 && arg0.type === 'StringLiteral') {
modelName = arg0.value;
options = node.arguments[1];
}
else {
modelName = 'modelValue';
options = arg0;
}
if (ctx.modelDecls[modelName]) {
ctx.error(`duplicate model name ${JSON.stringify(modelName)}`, node);
}
if (options) {
if (options.type !== 'ObjectExpression') {
ctx.error(`options must be an object expression`, options);
}
if (options.properties.find((p) => p.type === 'SpreadElement')) {
ctx.error(`options does not support spread properties.`, options);
}
}
const optionsString = options && ctx.getString(options);
ctx.modelDecls[modelName] = {
type,
options: optionsString,
identifier: declId && declId.type === 'Identifier' ? declId.name : undefined,
};
// register binding type
ctx.bindingMetadata[modelName] = compiler_dom_1.BindingTypes.PROPS;
const runtimeTypes = type && (0, resolveType_1.inferRuntimeType)(ctx, type, 'defineModel');
let runtimeType = runtimeTypes && runtimeTypes.length === 1 ? runtimeTypes[0] : undefined;
if (runtimeType) {
runtimeType = RUNTIME_TYPES[runtimeType] || runtimeType;
}
let runtimeOptions = '';
if (options) {
if (options.type === 'ObjectExpression') {
if (!runtimeType) {
// 未指定泛型,但指定了 options 中的 type
const type = options.properties.find((p) => p.type === 'ObjectProperty' &&
((p.key.type === 'Identifier' && p.key.name === 'type') ||
(p.key.type === 'StringLiteral' && p.key.value === 'type')));
if (type) {
if (type.value.type === 'TSAsExpression') {
// Array as PropType<string[]>
if (type.value.typeAnnotation.type === 'TSTypeReference' &&
type.value.typeAnnotation.typeParameters) {
runtimeType = ctx.getString(type.value.typeAnnotation.typeParameters.params[0]);
}
}
else {
runtimeType = ctx.getString(type.value);
}
}
}
const local = options.properties.find((p) => p.type === 'ObjectProperty' &&
((p.key.type === 'Identifier' && p.key.name === 'local') ||
(p.key.type === 'StringLiteral' && p.key.value === 'local')));
if (local) {
runtimeOptions = `{ ${ctx.getString(local)} }`;
}
else {
for (const p of options.properties) {
if (p.type === 'SpreadElement' || p.computed) {
runtimeOptions = optionsString;
break;
}
}
}
}
else {
runtimeOptions = optionsString;
}
}
ctx.s.overwrite(ctx.startOffset + node.start, ctx.startOffset + node.end, `${ctx.helper('useModel')}<${runtimeType || 'any'}>(__ins.props, ${JSON.stringify(modelName)}${runtimeOptions ? `, ${runtimeOptions}` : ``})`);
return true;
}
exports.processDefineModel = processDefineModel;
function genModelProps(ctx) {
if (!ctx.hasDefineModelCall)
return;
let modelPropsDecl = '';
for (const [name, { type, options }] of Object.entries(ctx.modelDecls)) {
let skipCheck = false;
let runtimeTypes = type && (0, resolveType_1.inferRuntimeType)(ctx, type, 'defineProps');
if (runtimeTypes) {
const hasUnknownType = runtimeTypes.includes(utils_1.UNKNOWN_TYPE);
runtimeTypes = runtimeTypes.filter((el) => {
if (el === utils_1.UNKNOWN_TYPE)
return false;
return true;
});
skipCheck = hasUnknownType && runtimeTypes.length > 0;
}
let runtimeType = (runtimeTypes &&
runtimeTypes.length > 0 &&
(0, utils_1.toRuntimeTypeString)(runtimeTypes)) ||
undefined;
const codegenOptions = (0, utils_1.concatStrings)([
runtimeType && `type: ${runtimeType}`,
skipCheck && 'skipCheck: true',
]);
let decl;
if (runtimeType && options) {
decl = `{ ${codegenOptions}, ...${options} }`;
}
else {
decl = options || (runtimeType ? `{ ${codegenOptions} }` : '{}');
}
modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},`;
}
return `{${modelPropsDecl}\n }`;
}
exports.genModelProps = genModelProps;
@@ -0,0 +1,4 @@
import type { Node } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare const DEFINE_OPTIONS = "defineOptions";
export declare function processDefineOptions(ctx: ScriptCompileContext, node: Node): boolean;
@@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processDefineOptions = exports.DEFINE_OPTIONS = void 0;
const utils_1 = require("./utils");
const defineProps_1 = require("./defineProps");
const defineEmits_1 = require("./defineEmits");
const defineExpose_1 = require("./defineExpose");
const defineSlots_1 = require("./defineSlots");
exports.DEFINE_OPTIONS = 'defineOptions';
function processDefineOptions(ctx, node) {
if (!(0, utils_1.isCallOf)(node, exports.DEFINE_OPTIONS)) {
return false;
}
if (ctx.hasDefineOptionsCall) {
ctx.error(`duplicate ${exports.DEFINE_OPTIONS}() call`, node);
}
if (node.typeParameters) {
ctx.error(`${exports.DEFINE_OPTIONS}() cannot accept type arguments`, node);
}
if (!node.arguments[0])
return true;
ctx.hasDefineOptionsCall = true;
ctx.optionsRuntimeDecl = (0, utils_1.unwrapTSNode)(node.arguments[0]);
let propsOption = undefined;
let emitsOption = undefined;
let exposeOption = undefined;
let slotsOption = undefined;
if (ctx.optionsRuntimeDecl.type === 'ObjectExpression') {
for (const prop of ctx.optionsRuntimeDecl.properties) {
if ((prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') &&
prop.key.type === 'Identifier') {
if (prop.key.name === 'props')
propsOption = prop;
if (prop.key.name === 'emits')
emitsOption = prop;
if (prop.key.name === 'expose')
exposeOption = prop;
if (prop.key.name === 'slots')
slotsOption = prop;
}
}
}
else {
ctx.error(`${exports.DEFINE_OPTIONS}() options must be an object expression`, ctx.optionsRuntimeDecl);
}
if (ctx.optionsRuntimeDecl.properties.find((p) => p.type === 'SpreadElement')) {
ctx.error(`options does not support spread properties.`, ctx.optionsRuntimeDecl);
}
if (propsOption) {
ctx.error(`${exports.DEFINE_OPTIONS}() cannot be used to declare props. Use ${defineProps_1.DEFINE_PROPS}() instead.`, propsOption);
}
if (emitsOption) {
ctx.error(`${exports.DEFINE_OPTIONS}() cannot be used to declare emits. Use ${defineEmits_1.DEFINE_EMITS}() instead.`, emitsOption);
}
if (exposeOption) {
ctx.error(`${exports.DEFINE_OPTIONS}() cannot be used to declare expose. Use ${defineExpose_1.DEFINE_EXPOSE}() instead.`, exposeOption);
}
if (slotsOption) {
ctx.error(`${exports.DEFINE_OPTIONS}() cannot be used to declare slots. Use ${defineSlots_1.DEFINE_SLOTS}() instead.`, slotsOption);
}
return true;
}
exports.processDefineOptions = processDefineOptions;
@@ -0,0 +1,17 @@
import type { Expression, LVal, Node } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare const DEFINE_PROPS = "defineProps";
export declare const WITH_DEFAULTS = "withDefaults";
export interface PropTypeData {
key: string;
type: string[];
required: boolean;
skipCheck: boolean;
}
export type PropsDestructureBindings = Record<string, // public prop key
{
local: string;
default?: Expression;
}>;
export declare function processDefineProps(ctx: ScriptCompileContext, node: Node, declId?: LVal): boolean;
export declare function genRuntimeProps(ctx: ScriptCompileContext): string | undefined;
@@ -0,0 +1,307 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genRuntimeProps = exports.processDefineProps = exports.WITH_DEFAULTS = exports.DEFINE_PROPS = void 0;
const shared_1 = require("@vue/shared");
const compiler_dom_1 = require("@vue/compiler-dom");
const resolveType_1 = require("./resolveType");
const utils_1 = require("./utils");
const defineModel_1 = require("./defineModel");
const analyzeScriptBindings_1 = require("./analyzeScriptBindings");
const definePropsDestructure_1 = require("./definePropsDestructure");
exports.DEFINE_PROPS = 'defineProps';
exports.WITH_DEFAULTS = 'withDefaults';
function processDefineProps(ctx, node, declId) {
if (!(0, utils_1.isCallOf)(node, exports.DEFINE_PROPS)) {
return processWithDefaults(ctx, node, declId);
}
if (node.arguments.length > 1) {
ctx.error(`${exports.DEFINE_PROPS}() can only accept one argument.`, node);
}
if (node.arguments.length > 0) {
const arg = node.arguments[0];
if (arg.type !== 'ArrayExpression' && arg.type !== 'ObjectExpression') {
ctx.error(`${exports.DEFINE_PROPS}() argument must be an object or array literal.`, arg);
}
}
if (ctx.hasDefinePropsCall) {
ctx.error(`duplicate ${exports.DEFINE_PROPS}() call`, node);
}
ctx.hasDefinePropsCall = true;
ctx.propsRuntimeDecl = node.arguments[0];
// register bindings
if (ctx.propsRuntimeDecl) {
for (const key of (0, analyzeScriptBindings_1.getObjectOrArrayExpressionKeys)(ctx.propsRuntimeDecl)) {
if (!(key in ctx.bindingMetadata)) {
ctx.bindingMetadata[key] = compiler_dom_1.BindingTypes.PROPS;
}
}
}
// call has type parameters - infer runtime types from it
if (node.typeParameters) {
if (ctx.propsRuntimeDecl) {
ctx.error(`${exports.DEFINE_PROPS}() cannot accept both type and non-type arguments ` +
`at the same time. Use one or the other.`, node);
}
ctx.propsTypeDecl = node.typeParameters.params[0];
}
// handle props destructure
if (declId && declId.type === 'ObjectPattern') {
(0, definePropsDestructure_1.processPropsDestructure)(ctx, declId);
}
ctx.propsCall = node;
ctx.propsDecl = declId;
return true;
}
exports.processDefineProps = processDefineProps;
function processWithDefaults(ctx, node, declId) {
if (!(0, utils_1.isCallOf)(node, exports.WITH_DEFAULTS)) {
return false;
}
if (!processDefineProps(ctx, node.arguments[0], declId)) {
ctx.error(`${exports.WITH_DEFAULTS}' first argument must be a ${exports.DEFINE_PROPS} call.`, node.arguments[0] || node);
}
if (node.arguments.length < 2) {
ctx.error(`${exports.WITH_DEFAULTS}' second argument is required.`, node.arguments[1] || node);
}
if (node.arguments[1].type !== 'ObjectExpression') {
ctx.error(`${exports.WITH_DEFAULTS}' second argument must be an object literal.`, node.arguments[1] || node);
}
if (node.arguments[1].properties.find((p) => p.type === 'SpreadElement')) {
ctx.error(`${exports.WITH_DEFAULTS} does not support spread properties in the second argument.`, node.arguments[1]);
}
if (ctx.propsRuntimeDecl) {
ctx.error(`${exports.WITH_DEFAULTS} can only be used with type-based ` +
`${exports.DEFINE_PROPS} declaration.`, node);
}
if (ctx.propsDestructureDecl) {
ctx.error(`${exports.WITH_DEFAULTS}() is unnecessary when using destructure with ${exports.DEFINE_PROPS}().\n` +
`Prefer using destructure default values, e.g. const { foo = 1 } = defineProps(...).`, node.callee);
}
ctx.propsRuntimeDefaults = node.arguments[1];
if (!ctx.propsRuntimeDefaults) {
ctx.error(`The 2nd argument of ${exports.WITH_DEFAULTS} is required.`, node);
}
ctx.propsCall = node;
return true;
}
function genRuntimeProps(ctx) {
let propsDecls;
if (ctx.propsRuntimeDecl) {
propsDecls = ctx.getString(ctx.propsRuntimeDecl).trim();
if (ctx.propsDestructureDecl) {
const defaults = [];
for (const key in ctx.propsDestructuredBindings) {
const d = genDestructuredDefaultValue(ctx, key);
const finalKey = (0, utils_1.getEscapedPropName)(key);
if (d)
defaults.push(`${finalKey}: ${d.valueString}${d.needSkipFactory ? `, __skip_${finalKey}: true` : ``}`);
}
if (defaults.length) {
propsDecls = `/*#__PURE__*/${ctx.helper(`mergeDefaults`)}(${propsDecls}, {\n ${defaults.join(',\n ')}\n})`;
}
}
}
else if (ctx.propsTypeDecl) {
propsDecls = genRuntimePropsFromTypes(ctx);
}
const modelsDecls = (0, defineModel_1.genModelProps)(ctx);
if (propsDecls && modelsDecls) {
return `/*#__PURE__*/${ctx.helper('mergeModels')}(${propsDecls}, ${modelsDecls})`;
}
else {
return modelsDecls || propsDecls;
}
}
exports.genRuntimeProps = genRuntimeProps;
function genRuntimePropsFromTypes(ctx) {
// this is only called if propsTypeDecl exists
const props = resolveRuntimePropsFromType(ctx, ctx.propsTypeDecl);
if (!props.length) {
return;
}
const propStrings = [];
const hasStaticDefaults = hasStaticWithDefaults(ctx);
for (const prop of props) {
propStrings.push(genRuntimePropFromType(ctx, prop, hasStaticDefaults));
// register bindings
if (!(prop.key in ctx.bindingMetadata)) {
ctx.bindingMetadata[prop.key] = compiler_dom_1.BindingTypes.PROPS;
}
}
let propsDecls = `{
${propStrings.join(',\n ')}\n }`;
if (ctx.propsRuntimeDefaults && !hasStaticDefaults) {
propsDecls = `/*#__PURE__*/${ctx.helper('mergeDefaults')}(${propsDecls}, ${ctx.getString(ctx.propsRuntimeDefaults)})`;
}
return propsDecls;
}
function parsePropType(ctx, node) {
if (node.type === 'TSPropertySignature') {
const typeAnn = node.typeAnnotation;
if (typeAnn) {
const tsType = typeAnn?.typeAnnotation;
if (tsType?.type === 'TSTypeReference') {
if (tsType.typeName.type === 'Identifier' &&
tsType.typeName.name === 'PropType') {
return [
`Object as ${ctx.source.slice(tsType.start + ctx.startOffset, tsType.end + ctx.startOffset)}`,
];
}
}
}
}
return [];
}
function resolveRuntimePropsFromType(ctx, node) {
const props = [];
const elements = (0, resolveType_1.resolveTypeElements)(ctx, node);
for (const key in elements.props) {
const e = elements.props[key];
let type = parsePropType(ctx, e);
let skipCheck = false;
if (type.length) {
skipCheck = true;
}
else {
type = (0, resolveType_1.inferRuntimeType)(ctx, e, 'defineProps');
// skip check for result containing unknown types
if (type.includes(utils_1.UNKNOWN_TYPE)) {
if (type.includes('Boolean') || type.includes('Function')) {
type = type.filter((t) => t !== utils_1.UNKNOWN_TYPE);
skipCheck = true;
}
else {
type = ['Object'];
}
}
}
let hasNull = false;
type = type || [];
if ((0, shared_1.isArray)(type)) {
if (type.find((t) => t === 'null')) {
hasNull = true;
type = type.filter((t) => t !== 'null');
}
}
props.push({
key,
required: !e.optional && !hasNull,
type,
skipCheck,
});
}
return props;
}
function genRuntimePropFromType(ctx, { key, required, type, skipCheck }, hasStaticDefaults) {
let defaultString;
const destructured = genDestructuredDefaultValue(ctx, key, type);
if (destructured) {
defaultString = `default: ${destructured.valueString}${destructured.needSkipFactory ? `, skipFactory: true` : ``}`;
}
else if (hasStaticDefaults) {
const prop = ctx.propsRuntimeDefaults.properties.find((node) => {
if (node.type === 'SpreadElement')
return false;
return (0, utils_1.resolveObjectKey)(node.key, node.computed) === key;
});
if (prop) {
if (prop.type === 'ObjectProperty') {
// prop has corresponding static default value
defaultString = `default: ${ctx.getString(prop.value)}`;
}
else {
defaultString = `${prop.async ? 'async ' : ''}${prop.kind !== 'method' ? `${prop.kind} ` : ''}default() ${ctx.getString(prop.body)}`;
}
}
}
const finalKey = (0, utils_1.getEscapedPropName)(key);
return `${finalKey}: { ${(0, utils_1.concatStrings)([
`type: ${(0, utils_1.toRuntimeTypeString)(type)}`,
`required: ${required}`,
skipCheck && 'skipCheck: true',
defaultString,
])} }`;
// if (!ctx.options.isProd) {
// return `${finalKey}: { ${concatStrings([
// `type: ${toRuntimeTypeString(type)}`,
// `required: ${required}`,
// skipCheck && 'skipCheck: true',
// defaultString,
// ])} }`
// } else if (
// type.some(
// (el) =>
// el === 'Boolean' ||
// ((!hasStaticDefaults || defaultString) && el === 'Function')
// )
// ) {
// // #4783 for boolean, should keep the type
// // #7111 for function, if default value exists or it's not static, should keep it
// // in production
// return `${finalKey}: { ${concatStrings([
// `type: ${toRuntimeTypeString(type)}`,
// defaultString,
// ])} }`
// } else {
// // production: checks are useless
// return `${finalKey}: ${defaultString ? `{ ${defaultString} }` : `{}`}`
// }
}
/**
* check defaults. If the default object is an object literal with only
* static properties, we can directly generate more optimized default
* declarations. Otherwise we will have to fallback to runtime merging.
*/
function hasStaticWithDefaults(ctx) {
return !!(ctx.propsRuntimeDefaults &&
ctx.propsRuntimeDefaults.type === 'ObjectExpression' &&
ctx.propsRuntimeDefaults.properties.every((node) => node.type !== 'SpreadElement' &&
(!node.computed || node.key.type.endsWith('Literal'))));
}
function genDestructuredDefaultValue(ctx, key, inferredType) {
const destructured = ctx.propsDestructuredBindings[key];
const defaultVal = destructured && destructured.default;
if (defaultVal) {
const value = ctx.getString(defaultVal);
const unwrapped = (0, utils_1.unwrapTSNode)(defaultVal);
if (inferredType && inferredType.length && !inferredType.includes('null')) {
const valueType = inferValueType(unwrapped);
if (valueType && !inferredType.includes(valueType)) {
ctx.error(`Default value of prop "${key}" does not match declared type.`, unwrapped);
}
}
// If the default value is a function or is an identifier referencing
// external value, skip factory wrap. This is needed when using
// destructure w/ runtime declaration since we cannot safely infer
// whether the expected runtime prop type is `Function`.
const needSkipFactory = !inferredType &&
((0, compiler_dom_1.isFunctionType)(unwrapped) || unwrapped.type === 'Identifier');
const needFactoryWrap = !needSkipFactory &&
!(0, utils_1.isLiteralNode)(unwrapped) &&
!inferredType?.includes('Function');
return {
valueString: needFactoryWrap ? `() => (${value})` : value,
needSkipFactory,
};
}
}
// non-comprehensive, best-effort type infernece for a runtime value
// this is used to catch default value / type declaration mismatches
// when using props destructure.
function inferValueType(node) {
switch (node.type) {
case 'StringLiteral':
return 'String';
case 'NumericLiteral':
return 'Number';
case 'BooleanLiteral':
return 'Boolean';
case 'ObjectExpression':
return 'Object';
case 'ArrayExpression':
return 'Array';
case 'FunctionExpression':
case 'ArrowFunctionExpression':
return 'Function';
}
}
@@ -0,0 +1,4 @@
import type { ObjectPattern } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare function processPropsDestructure(ctx: ScriptCompileContext, declId: ObjectPattern): void;
export declare function transformDestructuredProps(ctx: ScriptCompileContext, vueImportAliases: Record<string, string>): void;
@@ -0,0 +1,220 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformDestructuredProps = exports.processPropsDestructure = void 0;
const estree_walker_1 = require("estree-walker");
const compiler_dom_1 = require("@vue/compiler-dom");
const shared_1 = require("@vue/shared");
const utils_1 = require("./utils");
const defineProps_1 = require("./defineProps");
const warn_1 = require("../warn");
function processPropsDestructure(ctx, declId) {
if (!ctx.options.propsDestructure && !ctx.options.reactivityTransform) {
return;
}
(0, warn_1.warnOnce)(`This project is using reactive props destructure, which is an experimental ` +
`feature. It may receive breaking changes or be removed in the future, so ` +
`use at your own risk.\n` +
`To stay updated, follow the RFC at https://github.com/vuejs/rfcs/discussions/502.`);
ctx.propsDestructureDecl = declId;
const registerBinding = (key, local, defaultValue) => {
ctx.propsDestructuredBindings[key] = { local, default: defaultValue };
if (local !== key) {
ctx.bindingMetadata[local] = compiler_dom_1.BindingTypes.PROPS_ALIASED;
(ctx.bindingMetadata.__propsAliases ||
(ctx.bindingMetadata.__propsAliases = {}))[local] = key;
}
};
for (const prop of declId.properties) {
if (prop.type === 'ObjectProperty') {
const propKey = (0, utils_1.resolveObjectKey)(prop.key, prop.computed);
if (!propKey) {
ctx.error(`${defineProps_1.DEFINE_PROPS}() destructure cannot use computed key.`, prop.key);
}
if (prop.value.type === 'AssignmentPattern') {
// default value { foo = 123 }
const { left, right } = prop.value;
if (left.type !== 'Identifier') {
ctx.error(`${defineProps_1.DEFINE_PROPS}() destructure does not support nested patterns.`, left);
}
registerBinding(propKey, left.name, right);
}
else if (prop.value.type === 'Identifier') {
// simple destructure
registerBinding(propKey, prop.value.name);
}
else {
ctx.error(`${defineProps_1.DEFINE_PROPS}() destructure does not support nested patterns.`, prop.value);
}
}
else {
// rest spread
ctx.propsDestructureRestId = prop.argument.name;
// register binding
ctx.bindingMetadata[ctx.propsDestructureRestId] =
compiler_dom_1.BindingTypes.SETUP_REACTIVE_CONST;
}
}
}
exports.processPropsDestructure = processPropsDestructure;
function transformDestructuredProps(ctx, vueImportAliases) {
if (!ctx.options.propsDestructure && !ctx.options.reactivityTransform) {
return;
}
const rootScope = {};
const scopeStack = [rootScope];
let currentScope = rootScope;
const excludedIds = new WeakSet();
const parentStack = [];
const propsLocalToPublicMap = Object.create(null);
for (const key in ctx.propsDestructuredBindings) {
const { local } = ctx.propsDestructuredBindings[key];
rootScope[local] = true;
propsLocalToPublicMap[local] = key;
}
function pushScope() {
scopeStack.push((currentScope = Object.create(currentScope)));
}
function popScope() {
scopeStack.pop();
currentScope = scopeStack[scopeStack.length - 1] || null;
}
function registerLocalBinding(id) {
excludedIds.add(id);
if (currentScope) {
currentScope[id.name] = false;
}
else {
ctx.error('registerBinding called without active scope, something is wrong.', id);
}
}
function walkScope(node, isRoot = false) {
for (const stmt of node.body) {
if (stmt.type === 'VariableDeclaration') {
walkVariableDeclaration(stmt, isRoot);
}
else if (stmt.type === 'FunctionDeclaration' ||
stmt.type === 'ClassDeclaration') {
if (stmt.declare || !stmt.id)
continue;
registerLocalBinding(stmt.id);
}
else if ((stmt.type === 'ForOfStatement' || stmt.type === 'ForInStatement') &&
stmt.left.type === 'VariableDeclaration') {
walkVariableDeclaration(stmt.left);
}
else if (stmt.type === 'ExportNamedDeclaration' &&
stmt.declaration &&
stmt.declaration.type === 'VariableDeclaration') {
walkVariableDeclaration(stmt.declaration, isRoot);
}
else if (stmt.type === 'LabeledStatement' &&
stmt.body.type === 'VariableDeclaration') {
walkVariableDeclaration(stmt.body, isRoot);
}
}
}
function walkVariableDeclaration(stmt, isRoot = false) {
if (stmt.declare) {
return;
}
for (const decl of stmt.declarations) {
const isDefineProps = isRoot && decl.init && (0, utils_1.isCallOf)((0, utils_1.unwrapTSNode)(decl.init), 'defineProps');
for (const id of (0, compiler_dom_1.extractIdentifiers)(decl.id)) {
if (isDefineProps) {
// for defineProps destructure, only exclude them since they
// are already passed in as knownProps
excludedIds.add(id);
}
else {
registerLocalBinding(id);
}
}
}
}
function rewriteId(id, parent, parentStack) {
if ((parent.type === 'AssignmentExpression' && id === parent.left) ||
parent.type === 'UpdateExpression') {
ctx.error(`Cannot assign to destructured props as they are readonly.`, id);
}
if ((0, compiler_dom_1.isStaticProperty)(parent) && parent.shorthand) {
// let binding used in a property shorthand
// skip for destructure patterns
if (!parent.inPattern ||
(0, compiler_dom_1.isInDestructureAssignment)(parent, parentStack)) {
// { prop } -> { prop: __props.prop }
ctx.s.appendLeft(id.end + ctx.startOffset, `: ${(0, shared_1.genPropsAccessExp)(propsLocalToPublicMap[id.name])}`);
}
}
else {
// x --> __props.x
ctx.s.overwrite(id.start + ctx.startOffset, id.end + ctx.startOffset, (0, shared_1.genPropsAccessExp)(propsLocalToPublicMap[id.name]));
}
}
function checkUsage(node, method, alias = method) {
if ((0, utils_1.isCallOf)(node, alias)) {
const arg = (0, utils_1.unwrapTSNode)(node.arguments[0]);
if (arg.type === 'Identifier' && currentScope[arg.name]) {
ctx.error(`"${arg.name}" is a destructured prop and should not be passed directly to ${method}(). ` +
`Pass a getter () => ${arg.name} instead.`, arg);
}
}
}
// check root scope first
const ast = ctx.scriptSetupAst;
walkScope(ast, true);
(0, estree_walker_1.walk)(ast, {
enter(node, parent) {
parent && parentStack.push(parent);
// skip type nodes
if (parent &&
parent.type.startsWith('TS') &&
parent.type !== 'TSAsExpression' &&
parent.type !== 'TSNonNullExpression' &&
parent.type !== 'TSTypeAssertion') {
return this.skip();
}
checkUsage(node, 'watch', vueImportAliases.watch);
checkUsage(node, 'toRef', vueImportAliases.toRef);
// function scopes
if ((0, compiler_dom_1.isFunctionType)(node)) {
pushScope();
(0, compiler_dom_1.walkFunctionParams)(node, registerLocalBinding);
if (node.body.type === 'BlockStatement') {
walkScope(node.body);
}
return;
}
// catch param
if (node.type === 'CatchClause') {
pushScope();
if (node.param && node.param.type === 'Identifier') {
registerLocalBinding(node.param);
}
walkScope(node.body);
return;
}
// non-function block scopes
if (node.type === 'BlockStatement' && !(0, compiler_dom_1.isFunctionType)(parent)) {
pushScope();
walkScope(node);
return;
}
if (node.type === 'Identifier') {
if ((0, compiler_dom_1.isReferencedIdentifier)(node, parent, parentStack) &&
!excludedIds.has(node)) {
if (currentScope[node.name]) {
rewriteId(node, parent, parentStack);
}
}
}
},
leave(node, parent) {
parent && parentStack.pop();
if ((node.type === 'BlockStatement' && !(0, compiler_dom_1.isFunctionType)(parent)) ||
(0, compiler_dom_1.isFunctionType)(node)) {
popScope();
}
},
});
}
exports.transformDestructuredProps = transformDestructuredProps;
@@ -0,0 +1,5 @@
import { type LVal, type Node } from '@babel/types';
import type { ScriptCompileContext } from './context';
export declare const DEFINE_SLOTS = "defineSlots";
export declare function processDefineSlots(ctx: ScriptCompileContext, node: Node, declId?: LVal): boolean;
export declare function genRuntimeSlots(ctx: ScriptCompileContext): string | undefined;
@@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genRuntimeSlots = exports.processDefineSlots = exports.DEFINE_SLOTS = void 0;
const types_1 = require("@babel/types");
const utils_1 = require("./utils");
exports.DEFINE_SLOTS = 'defineSlots';
function processDefineSlots(ctx, node, declId) {
if (!(0, utils_1.isCallOf)(node, exports.DEFINE_SLOTS)) {
return false;
}
if (ctx.hasDefineSlotsCall) {
ctx.error(`duplicate ${exports.DEFINE_SLOTS}() call`, node);
}
ctx.hasDefineSlotsCall = true;
if (node.arguments.length > 0) {
ctx.error(`${exports.DEFINE_SLOTS}() cannot accept arguments`, node);
}
if (node.typeParameters &&
node.typeParameters.params.length === 1 &&
(0, types_1.isTSTypeLiteral)(node.typeParameters.params[0])) {
ctx.slotsRuntimeDecl = node.typeParameters.params[0];
}
if (declId) {
ctx.s.overwrite(ctx.startOffset + node.start, ctx.startOffset + node.end, `${ctx.helper('useSlots')}()`);
}
return true;
}
exports.processDefineSlots = processDefineSlots;
function genRuntimeSlots(ctx) {
if (!ctx.slotsRuntimeDecl) {
return;
}
const slots = [];
ctx.slotsRuntimeDecl.members.forEach((member) => {
if ((0, types_1.isTSMethodSignature)(member) &&
member.parameters.length === 1 &&
(0, types_1.isIdentifier)(member.key)) {
const param = member.parameters[0];
if ((0, types_1.isIdentifier)(param) && param.typeAnnotation) {
const typeAnn = param.typeAnnotation;
slots.push(member.key.name +
': ' +
ctx.source.slice(ctx.startOffset + typeAnn.start + 1, ctx.startOffset + typeAnn.end));
}
}
});
if (!slots.length) {
return;
}
return `Object as SlotsType<{${slots.join(';')}}>`;
}
exports.genRuntimeSlots = genRuntimeSlots;
@@ -0,0 +1,14 @@
import type { BindingMetadata, SFCDescriptor } from '@vue/compiler-sfc';
import type { ScriptCompileContext } from './context';
import type { TransformPluginContext } from 'rollup';
export declare function processNormalScript(ctx: ScriptCompileContext, _scopeId: string): import("@vue/compiler-sfc").SFCScriptBlock;
export declare function processTemplate(sfc: SFCDescriptor, { relativeFilename, bindingMetadata, className, rootDir, }: {
relativeFilename: string;
bindingMetadata?: BindingMetadata;
className: string;
rootDir: string;
}, pluginContext?: TransformPluginContext): {
code: string;
map: import("source-map-js").RawSourceMap | undefined;
preamble: string | undefined;
};
@@ -0,0 +1,119 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processTemplate = exports.processNormalScript = void 0;
const magic_string_1 = __importDefault(require("magic-string"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const analyzeScriptBindings_1 = require("./analyzeScriptBindings");
const rewriteConsole_1 = require("./rewriteConsole");
const rewriteDebugError_1 = require("./rewriteDebugError");
const rewriteSourceMap_1 = require("./rewriteSourceMap");
const rewriteDefault_1 = require("../rewriteDefault");
const utils_1 = require("./utils");
const template_1 = require("../../template");
const utils_2 = require("../../../../../utils");
const template_2 = require("../../../code/template");
function processNormalScript(ctx, _scopeId) {
const script = ctx.descriptor.script;
// if (script.lang && !ctx.isJS && !ctx.isTS) {
// // do not process non js/ts script blocks
// return script
// }
try {
let content = script.content;
let map = script.map;
const scriptAst = ctx.scriptAst;
const bindings = (0, analyzeScriptBindings_1.analyzeScriptBindings)(scriptAst.body);
const s = new magic_string_1.default(content);
const relativeFilename = ctx.descriptor.relativeFilename;
const startLine = (ctx.descriptor.script.loc.start.line || 1) - 1;
const startOffset = 0;
if (ctx.options.genDefaultAs) {
(0, rewriteDefault_1.rewriteDefaultAST)(scriptAst.body, s, ctx.options.genDefaultAs, (0, utils_1.resolveDefineCode)(ctx.options.componentType));
}
if (process.env.NODE_ENV === 'development' ||
process.env.UNI_RUST_TEST === 'true') {
if ((0, rewriteDebugError_1.hasDebugError)(content)) {
(0, rewriteDebugError_1.rewriteDebugError)(scriptAst, s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
if ((0, rewriteConsole_1.hasConsole)(content)) {
(0, rewriteConsole_1.rewriteConsole)(scriptAst, s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
(0, rewriteSourceMap_1.rewriteSourceMap)(scriptAst, s, {
fileName: relativeFilename,
startLine,
startOffset,
});
}
if (ctx.options.genDefaultAs) {
s.append(`\nexport default ${ctx.options.genDefaultAs}`);
}
if (s.hasChanged()) {
content = s.toString();
// 需要合并旧的 sourcemap
// if (ctx.options.sourceMap) {
// map = s.generateMap({
// source: relativeFilename,
// hires: true,
// includeContent: true,
// }) as unknown as RawSourceMap
// }
}
return {
...script,
content,
map,
bindings,
scriptAst: scriptAst.body,
};
}
catch (e) {
// silently fallback if parse fails since user may be using custom
// babel syntax
return script;
}
}
exports.processNormalScript = processNormalScript;
function processTemplate(sfc, { relativeFilename, bindingMetadata, className, rootDir, }, pluginContext) {
const options = (0, template_1.resolveGenTemplateCodeOptions)(relativeFilename, sfc.source, sfc, {
mode: 'module',
inline: !!sfc.scriptSetup,
className,
rootDir,
sourceMap: (0, uni_cli_shared_1.enableSourceMap)(),
bindingMetadata,
}, pluginContext);
const { code, preamble, elements, map, easyComponentAutoImports } = (0, template_2.genTemplateCode)(sfc, options);
if (easyComponentAutoImports) {
Object.keys(easyComponentAutoImports).forEach((source) => {
(0, uni_cli_shared_1.addUTSEasyComAutoImports)(source, easyComponentAutoImports[source]);
});
}
if (process.env.NODE_ENV === 'production') {
const components = elements.filter((element) => {
// 如果是UTS原生组件,则无需记录摇树
if (options.parseUTSComponent(element, 'kotlin')) {
return false;
}
return true;
});
if (process.env.UNI_COMPILE_TARGET === 'uni_modules') {
(0, uni_cli_shared_1.addUniModulesExtApiComponents)(relativeFilename, components);
}
else {
(0, utils_2.addExtApiComponents)(components);
}
}
return { code, map, preamble };
}
exports.processTemplate = processTemplate;
@@ -0,0 +1,68 @@
import type { Node, Statement, TSCallSignatureDeclaration, TSFunctionType, TSMethodSignature, TSModuleDeclaration, TSPropertySignature } from '@babel/types';
import { type ScriptCompileContext } from './context';
import type { ImportBinding } from '../compileScript';
/**
* TypeResolveContext is compatible with ScriptCompileContext
* but also allows a simpler version of it with minimal required properties
* when resolveType needs to be used in a non-SFC context, e.g. in a babel
* plugin. The simplest context can be just:
* ```ts
* const ctx: SimpleTypeResolveContext = {
* filename: '...',
* source: '...',
* options: {},
* error() {},
* ast: []
* }
* ```
*/
export type SimpleTypeResolveContext = Pick<ScriptCompileContext, 'source' | 'filename' | 'error' | 'options'> & Partial<Pick<ScriptCompileContext, 'scope' | 'globalScopes' | 'deps' | 'fs'>> & {
ast: Statement[];
};
export type TypeResolveContext = ScriptCompileContext | SimpleTypeResolveContext;
type Import = Pick<ImportBinding, 'source' | 'imported'>;
interface WithScope {
_ownerScope: TypeScope;
}
type ScopeTypeNode = Node & WithScope & {
_ns?: TSModuleDeclaration & WithScope;
};
export declare class TypeScope {
filename: string;
source: string;
offset: number;
imports: Record<string, Import>;
types: Record<string, ScopeTypeNode>;
declares: Record<string, ScopeTypeNode>;
constructor(filename: string, source: string, offset?: number, imports?: Record<string, Import>, types?: Record<string, ScopeTypeNode>, declares?: Record<string, ScopeTypeNode>);
resolvedImportSources: Record<string, string>;
exportedTypes: Record<string, ScopeTypeNode>;
exportedDeclares: Record<string, ScopeTypeNode>;
}
export interface MaybeWithScope {
_ownerScope?: TypeScope;
}
interface ResolvedElements {
props: Record<string, (TSPropertySignature | TSMethodSignature) & {
_ownerScope: TypeScope;
}>;
calls?: (TSCallSignatureDeclaration | TSFunctionType)[];
}
/**
* Resolve arbitrary type node to a list of type elements that can be then
* mapped to runtime props or emits.
*/
export declare function resolveTypeElements(ctx: TypeResolveContext, node: Node & MaybeWithScope & {
_resolvedElements?: ResolvedElements;
}, scope?: TypeScope, typeParameters?: Record<string, Node>): ResolvedElements;
/**
* @private
*/
export declare function invalidateTypeCache(filename: string): void;
export declare function fileToScope(ctx: TypeResolveContext, filename: string, asGlobal?: boolean): TypeScope;
export declare function recordImports(body: Statement[]): Record<string, Import>;
export declare function inferRuntimeType(ctx: TypeResolveContext, node: Node & MaybeWithScope, from?: 'defineProps' | 'defineModel', scope?: TypeScope): string[];
export declare function resolveUnionType(ctx: TypeResolveContext, node: Node & MaybeWithScope & {
_resolvedElements?: ResolvedElements;
}, scope?: TypeScope): Node[];
export {};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
import type { Program } from '@babel/types';
import type MagicString from 'magic-string';
export declare function hasConsole(content: string): boolean;
export declare function rewriteConsole(ast: Program, s: MagicString, { fileName, startLine, startOffset, }: {
fileName: string;
startLine: number;
startOffset: number;
}): void;
@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteConsole = exports.hasConsole = void 0;
const estree_walker_1 = require("estree-walker");
function hasConsole(content) {
return content.includes('console.');
}
exports.hasConsole = hasConsole;
function rewriteConsole(ast, s, { fileName, startLine, startOffset, }) {
(0, estree_walker_1.walk)(ast, {
enter(node, _parent) {
if (node.type === 'CallExpression' && node.loc) {
const callee = node.callee;
if (callee.type === 'MemberExpression') {
// console.log()
// UTSAndroid.consoleDebugError()
if (callee.object.type === 'Identifier' &&
callee.property.type === 'Identifier' &&
(callee.object.name === 'console' ||
callee.property.name === 'consoleDebugError')) {
const at = `${node.arguments.length ? ', " ' : '"'}at ${fileName}:${node.loc.start.line + startLine}"`;
s.appendRight(startOffset + node.end - 1, at);
}
}
}
},
});
}
exports.rewriteConsole = rewriteConsole;
@@ -0,0 +1,10 @@
import type { Program } from '@babel/types';
import type MagicString from 'magic-string';
export declare function hasDebugError(content: string): boolean;
interface RewriteDebugErrorOptions {
fileName: string;
startLine: number;
startOffset: number;
}
export declare function rewriteDebugError(ast: Program, s: MagicString, options: RewriteDebugErrorOptions): void;
export {};
@@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteDebugError = exports.hasDebugError = void 0;
const estree_walker_1 = require("estree-walker");
const DEBUG_ERROR_RE = /(JSON\.parse)|(codeURI)/;
function hasDebugError(content) {
return DEBUG_ERROR_RE.test(content);
}
exports.hasDebugError = hasDebugError;
function rewriteDebugError(ast, s, options) {
(0, estree_walker_1.walk)(ast, {
enter(node, _parent) {
if (node.type === 'CallExpression' && node.loc) {
const callee = node.callee;
if (callee.type === 'MemberExpression') {
// JSON.parse || JSON.parseObject || JSON.parseArray
//
if (callee.object.type === 'Identifier' &&
callee.property.type === 'Identifier' &&
callee.object.name === 'JSON') {
const name = callee.property.name;
if (name === 'parse' ||
name === 'parseObject' ||
name === 'parseArray') {
wrapConsoleDebugError(s, node, options);
}
}
}
else if (callee.type === 'Identifier' &&
METHODS.includes(callee.name)) {
wrapConsoleDebugError(s, node, options);
}
}
},
});
}
exports.rewriteDebugError = rewriteDebugError;
function wrapConsoleDebugError(s, node, { fileName, startLine, startOffset }) {
s.appendLeft(startOffset + node.start, `UTSAndroid.consoleDebugError(`);
s.appendRight(startOffset + node.end, `)`);
const at = `, " at ${fileName}:${node.loc.start.line + startLine}"`;
s.appendLeft(startOffset + node.end, at);
}
const METHODS = [
'decodeURI',
'decodeURIComponent',
'encodeURI',
'encodeURIComponent',
];
@@ -0,0 +1,7 @@
import type { Program } from '@babel/types';
import type MagicString from 'magic-string';
export declare function rewriteSourceMap(ast: Program, s: MagicString, { fileName, startLine, startOffset, }: {
fileName: string;
startLine: number;
startOffset: number;
}): void;
@@ -0,0 +1,83 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteSourceMap = void 0;
const estree_walker_1 = require("estree-walker");
function rewriteSourceMap(ast, s, { fileName, startLine, startOffset, }) {
// 暂时屏蔽
// if (true) {
// return
// }
const isDev = process.env.NODE_ENV === 'development' ||
// rust 测试使用
process.env.UNI_RUST_TEST_NODE_ENV === 'development';
if (!isDev) {
return;
}
if (fileName.includes('/@dcloudio/')) {
return;
}
(0, estree_walker_1.walk)(ast, {
enter(node, _parent) {
// const a = {}
if (node.type === 'VariableDeclarator' &&
node.init &&
node.init.loc &&
node.id.type === 'Identifier') {
const { id, init } = node;
if (init.type === 'ObjectExpression') {
let isJsonObj = false;
if (!id.typeAnnotation) {
isJsonObj = true;
}
else if (id.typeAnnotation &&
id.typeAnnotation.type === 'TSTypeAnnotation' &&
id.typeAnnotation.typeAnnotation.type === 'TSTypeReference') {
const { typeName } = id.typeAnnotation.typeAnnotation;
if (typeName.type === 'Identifier' &&
typeName.name === 'UTSJSONObject') {
isJsonObj = true;
}
}
if (isJsonObj) {
const start = id.loc.start;
s.appendRight(startOffset + init.start + 1, `__$originalPosition: new UTSSourceMapPosition("${id.name}", "${fileName}", ${startLine + start.line}, ${start.column + 1}),`);
}
}
else if (init.type === 'TSAsExpression' &&
init.typeAnnotation.type === 'TSTypeReference' &&
init.expression.type === 'ObjectExpression') {
const { typeName } = init.typeAnnotation;
if (typeName.type === 'Identifier' &&
typeName.name === 'UTSJSONObject') {
const start = id.loc.start;
s.appendRight(startOffset + init.start + 1, ` __$originalPosition: new UTSSourceMapPosition("${id.name}", "${fileName}", ${startLine + start.line}, ${start.column + 1}), `);
}
}
else if (init.type === 'NewExpression' &&
init.callee.type === 'Identifier' &&
init.callee.name === 'UTSJSONObject') {
const start = node.id.loc.start;
s.appendRight(startOffset + init.end - 1, `${init.arguments.length > 0 ? ', ' : ''}new UTSSourceMapPosition("${node.id.name}", "${fileName}", ${startLine + start.line}, ${start.column + 1})`);
}
}
else if (node.type === 'TSTypeAliasDeclaration' &&
node.typeAnnotation.type === 'TSTypeLiteral' &&
node.id.type === 'Identifier') {
const start = node.id.loc.start;
s.appendRight(startOffset + node.typeAnnotation.start + 1, ` __$originalPosition?: UTSSourceMapPosition<"${node.id.name}", "${fileName}", ${startLine + start.line}, ${start.column + 1}>;`);
}
else if (node.type === 'ClassDeclaration') {
if (node.implements && node.implements.length > 0) {
// 已有接口
s.appendRight(startOffset + node.body.start, `, IUTSSourceMap`);
}
else {
s.appendRight(startOffset + node.body.start, ` implements IUTSSourceMap`);
}
const start = node.id.loc.start;
s.appendRight(startOffset + node.body.start + 1, `\n// @ts-expect-error \noverride __$getOriginalPosition(): UTSSourceMapPosition { return new UTSSourceMapPosition("${node.id.name}", "${fileName}", ${startLine + start.line}, ${start.column + 1});}\n`);
}
},
});
}
exports.rewriteSourceMap = rewriteSourceMap;
@@ -0,0 +1,29 @@
import type { CallExpression, Expression, Identifier, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, Node, StringLiteral } from '@babel/types';
import type { SFCScriptCompileOptions } from '../compileScript';
export declare const UNKNOWN_TYPE = "Unknown";
export declare function resolveDefineCode(componentType: SFCScriptCompileOptions['componentType']): "defineApp" | "defineComponent";
export declare function resolveObjectKey(node: Node, computed: boolean): string | undefined;
export declare function concatStrings(strs: Array<string | null | undefined | false>): string;
export declare function isLiteralNode(node: Node): boolean;
export declare function unwrapTSNode(node: Node): Node;
export declare function isCallOf(node: Node | null | undefined, test: string | ((id: string) => boolean) | null | undefined): node is CallExpression;
export declare function toRuntimeTypeString(types: string[]): string;
export declare function getImportedName(specifier: ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier): string;
export declare function getId(node: Identifier | StringLiteral): string;
export declare function getId(node: Expression): string | null;
/**
* We need `getCanonicalFileName` when creating ts module resolution cache,
* but TS does not expose it directly. This implementation is repllicated from
* the TS source code.
*/
export declare function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): (str: string) => string;
export declare function normalizePath(p: string): string;
export declare const joinPaths: (...paths: string[]) => string;
/**
* key may contain symbols
* e.g. onUpdate:modelValue -> "onUpdate:modelValue"
*/
export declare const propNameEscapeSymbolsRE: RegExp;
export declare function getEscapedPropName(key: string): string;
export declare const cssVarNameEscapeSymbolsRE: RegExp;
export declare function getEscapedCssVarName(key: string, doubleEscape: boolean): string;
@@ -0,0 +1,118 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getEscapedCssVarName = exports.cssVarNameEscapeSymbolsRE = exports.getEscapedPropName = exports.propNameEscapeSymbolsRE = exports.joinPaths = exports.normalizePath = exports.createGetCanonicalFileName = exports.getId = exports.getImportedName = exports.toRuntimeTypeString = exports.isCallOf = exports.unwrapTSNode = exports.isLiteralNode = exports.concatStrings = exports.resolveObjectKey = exports.resolveDefineCode = exports.UNKNOWN_TYPE = void 0;
const path_1 = __importDefault(require("path"));
const compiler_dom_1 = require("@vue/compiler-dom");
exports.UNKNOWN_TYPE = 'Unknown';
function resolveDefineCode(componentType) {
return componentType === 'app'
? `defineApp`
: componentType === 'page'
? `defineComponent` //`definePage`
: `defineComponent`;
}
exports.resolveDefineCode = resolveDefineCode;
function resolveObjectKey(node, computed) {
switch (node.type) {
case 'StringLiteral':
case 'NumericLiteral':
return String(node.value);
case 'Identifier':
if (!computed)
return node.name;
}
return undefined;
}
exports.resolveObjectKey = resolveObjectKey;
function concatStrings(strs) {
return strs.filter((s) => !!s).join(', ');
}
exports.concatStrings = concatStrings;
function isLiteralNode(node) {
return node.type.endsWith('Literal');
}
exports.isLiteralNode = isLiteralNode;
function unwrapTSNode(node) {
if (compiler_dom_1.TS_NODE_TYPES.includes(node.type)) {
return unwrapTSNode(node.expression);
}
else {
return node;
}
}
exports.unwrapTSNode = unwrapTSNode;
function isCallOf(node, test) {
return !!(node &&
test &&
node.type === 'CallExpression' &&
node.callee.type === 'Identifier' &&
(typeof test === 'string'
? node.callee.name === test
: test(node.callee.name)));
}
exports.isCallOf = isCallOf;
function toRuntimeTypeString(types) {
return types.length > 1 ? `[${types.join(', ')}]` : types[0] || `Object`;
}
exports.toRuntimeTypeString = toRuntimeTypeString;
function getImportedName(specifier) {
if (specifier.type === 'ImportSpecifier')
return specifier.imported.type === 'Identifier'
? specifier.imported.name
: specifier.imported.value;
else if (specifier.type === 'ImportNamespaceSpecifier')
return '*';
return 'default';
}
exports.getImportedName = getImportedName;
function getId(node) {
return node.type === 'Identifier'
? node.name
: node.type === 'StringLiteral'
? node.value
: null;
}
exports.getId = getId;
const identity = (str) => str;
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g;
const toLowerCase = (str) => str.toLowerCase();
function toFileNameLowerCase(x) {
return fileNameLowerCaseRegExp.test(x)
? x.replace(fileNameLowerCaseRegExp, toLowerCase)
: x;
}
/**
* We need `getCanonicalFileName` when creating ts module resolution cache,
* but TS does not expose it directly. This implementation is repllicated from
* the TS source code.
*/
function createGetCanonicalFileName(useCaseSensitiveFileNames) {
return useCaseSensitiveFileNames ? identity : toFileNameLowerCase;
}
exports.createGetCanonicalFileName = createGetCanonicalFileName;
// in the browser build, the polyfill doesn't expose posix, but defaults to
// posix behavior.
const normalize = (path_1.default.posix || path_1.default).normalize;
const windowsSlashRE = /\\/g;
function normalizePath(p) {
return normalize(p.replace(windowsSlashRE, '/'));
}
exports.normalizePath = normalizePath;
exports.joinPaths = (path_1.default.posix || path_1.default).join;
/**
* key may contain symbols
* e.g. onUpdate:modelValue -> "onUpdate:modelValue"
*/
exports.propNameEscapeSymbolsRE = /[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~\-]/;
function getEscapedPropName(key) {
return exports.propNameEscapeSymbolsRE.test(key) ? JSON.stringify(key) : key;
}
exports.getEscapedPropName = getEscapedPropName;
exports.cssVarNameEscapeSymbolsRE = /[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g;
function getEscapedCssVarName(key, doubleEscape) {
return key.replace(exports.cssVarNameEscapeSymbolsRE, (s) => doubleEscape ? `\\\\${s}` : `\\${s}`);
}
exports.getEscapedCssVarName = getEscapedCssVarName;
@@ -0,0 +1,9 @@
/// <reference types="node" />
import { type UrlWithStringQuery } from 'url';
export declare function isRelativeUrl(url: string): boolean;
export declare function isExternalUrl(url: string): boolean;
export declare function isDataUrl(url: string): boolean;
/**
* Parses string url into URL object.
*/
export declare function parseUrl(url: string): UrlWithStringQuery;
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseUrl = exports.isDataUrl = exports.isExternalUrl = exports.isRelativeUrl = void 0;
const url_1 = require("url");
const shared_1 = require("@vue/shared");
function isRelativeUrl(url) {
const firstChar = url.charAt(0);
return firstChar === '.' || firstChar === '~' || firstChar === '@';
}
exports.isRelativeUrl = isRelativeUrl;
const externalRE = /^(https?:)?\/\//;
function isExternalUrl(url) {
return externalRE.test(url);
}
exports.isExternalUrl = isExternalUrl;
const dataUrlRE = /^\s*data:/i;
function isDataUrl(url) {
return dataUrlRE.test(url);
}
exports.isDataUrl = isDataUrl;
/**
* Parses string url into URL object.
*/
function parseUrl(url) {
const firstChar = url.charAt(0);
if (firstChar === '~') {
const secondChar = url.charAt(1);
url = url.slice(secondChar === '/' ? 2 : 1);
}
return parseUriParts(url);
}
exports.parseUrl = parseUrl;
/**
* vuejs/component-compiler-utils#22 Support uri fragment in transformed require
* @param urlString - an url as a string
*/
function parseUriParts(urlString) {
// A TypeError is thrown if urlString is not a string
// @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
return (0, url_1.parse)((0, shared_1.isString)(urlString) ? urlString : '', false, true);
}
@@ -0,0 +1,33 @@
import { type NodeTransform } from '@vue/compiler-core';
export interface AssetURLTagConfig {
[name: string]: string[];
}
export interface AssetURLOptions {
/**
* If base is provided, instead of transforming relative asset urls into
* imports, they will be directly rewritten to absolute urls.
*/
base?: string | null;
/**
* If true, also processes absolute urls.
*/
includeAbsolute?: boolean;
tags?: AssetURLTagConfig;
}
export declare const defaultAssetUrlOptions: Required<AssetURLOptions>;
export declare const normalizeOptions: (options: AssetURLOptions | AssetURLTagConfig) => Required<AssetURLOptions>;
export declare const createAssetUrlTransformWithOptions: (options: Required<AssetURLOptions>) => NodeTransform;
/**
* A `@vue/compiler-core` plugin that transforms relative asset urls into
* either imports or absolute urls.
*
* ``` js
* // Before
* createVNode('img', { src: './logo.png' })
*
* // After
* import _imports_0 from './logo.png'
* createVNode('img', { src: _imports_0 })
* ```
*/
export declare const transformAssetUrl: NodeTransform;
@@ -0,0 +1,148 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformAssetUrl = exports.createAssetUrlTransformWithOptions = exports.normalizeOptions = exports.defaultAssetUrlOptions = void 0;
const path_1 = __importDefault(require("path"));
const compiler_core_1 = require("@vue/compiler-core");
const templateUtils_1 = require("./templateUtils");
const shared_1 = require("@vue/shared");
exports.defaultAssetUrlOptions = {
base: null,
includeAbsolute: false,
tags: {
video: ['src', 'poster'],
source: ['src'],
img: ['src'],
image: ['xlink:href', 'href'],
use: ['xlink:href', 'href'],
},
};
const normalizeOptions = (options) => {
if (Object.keys(options).some((key) => (0, shared_1.isArray)(options[key]))) {
// legacy option format which directly passes in tags config
return {
...exports.defaultAssetUrlOptions,
tags: options,
};
}
return {
...exports.defaultAssetUrlOptions,
...options,
};
};
exports.normalizeOptions = normalizeOptions;
const createAssetUrlTransformWithOptions = (options) => {
return (node, context) => exports.transformAssetUrl(node, context, options);
};
exports.createAssetUrlTransformWithOptions = createAssetUrlTransformWithOptions;
/**
* A `@vue/compiler-core` plugin that transforms relative asset urls into
* either imports or absolute urls.
*
* ``` js
* // Before
* createVNode('img', { src: './logo.png' })
*
* // After
* import _imports_0 from './logo.png'
* createVNode('img', { src: _imports_0 })
* ```
*/
const transformAssetUrl = (node, context, options = exports.defaultAssetUrlOptions) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
if (!node.props.length) {
return;
}
const tags = options.tags || exports.defaultAssetUrlOptions.tags;
const attrs = tags[node.tag];
const wildCardAttrs = tags['*'];
if (!attrs && !wildCardAttrs) {
return;
}
const assetAttrs = (attrs || []).concat(wildCardAttrs || []);
node.props.forEach((attr, index) => {
if (attr.type !== compiler_core_1.NodeTypes.ATTRIBUTE ||
!assetAttrs.includes(attr.name) ||
!attr.value ||
(0, templateUtils_1.isExternalUrl)(attr.value.content) ||
(0, templateUtils_1.isDataUrl)(attr.value.content) ||
attr.value.content[0] === '#' ||
(!options.includeAbsolute && !(0, templateUtils_1.isRelativeUrl)(attr.value.content))) {
return;
}
const url = (0, templateUtils_1.parseUrl)(attr.value.content);
if (options.base && attr.value.content[0] === '.') {
// explicit base - directly rewrite relative urls into absolute url
// to avoid generating extra imports
// Allow for full hostnames provided in options.base
const base = (0, templateUtils_1.parseUrl)(options.base);
const protocol = base.protocol || '';
const host = base.host ? protocol + '//' + base.host : '';
const basePath = base.path || '/';
// when packaged in the browser, path will be using the posix-
// only version provided by rollup-plugin-node-builtins.
attr.value.content =
host +
(path_1.default.posix || path_1.default).join(basePath, url.path + (url.hash || ''));
return;
}
// otherwise, transform the url into an import.
// this assumes a bundler will resolve the import into the correct
// absolute url (e.g. webpack file-loader)
const exp = getImportsExpressionExp(url.path, url.hash, attr.loc, context);
node.props[index] = {
type: compiler_core_1.NodeTypes.DIRECTIVE,
name: 'bind',
arg: (0, compiler_core_1.createSimpleExpression)(attr.name, true, attr.loc),
exp,
modifiers: [],
loc: attr.loc,
};
});
}
};
exports.transformAssetUrl = transformAssetUrl;
function getImportsExpressionExp(path, hash, loc, context) {
if (path) {
let name;
let exp;
const existingIndex = context.imports.findIndex((i) => i.path === path);
if (existingIndex > -1) {
name = `_imports_${existingIndex}`;
exp = context.imports[existingIndex].exp;
}
else {
name = `_imports_${context.imports.length}`;
exp = (0, compiler_core_1.createSimpleExpression)(name, false, loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
// We need to ensure the path is not encoded (to %2F),
// so we decode it back in case it is encoded
context.imports.push({
exp,
path: decodeURIComponent(path),
});
}
if (!hash) {
return exp;
}
const hashExp = `${name} + '${hash}'`;
const finalExp = (0, compiler_core_1.createSimpleExpression)(hashExp, false, loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
if (!context.hoistStatic) {
return finalExp;
}
const existingHoistIndex = context.hoists.findIndex((h) => {
return (h &&
h.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
!h.isStatic &&
h.content === hashExp);
});
if (existingHoistIndex > -1) {
return (0, compiler_core_1.createSimpleExpression)(`_hoisted_${existingHoistIndex + 1}`, false, loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
}
return context.hoist(finalExp);
}
else {
return (0, compiler_core_1.createSimpleExpression)(`''`, false, loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
}
}
@@ -0,0 +1,4 @@
import { type NodeTransform } from '@vue/compiler-core';
import { type AssetURLOptions } from './transformAssetUrl';
export declare const createSrcsetTransformWithOptions: (options: Required<AssetURLOptions>) => NodeTransform;
export declare const transformSrcset: NodeTransform;
@@ -0,0 +1,131 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformSrcset = exports.createSrcsetTransformWithOptions = void 0;
const path_1 = __importDefault(require("path"));
const compiler_core_1 = require("@vue/compiler-core");
const templateUtils_1 = require("./templateUtils");
const transformAssetUrl_1 = require("./transformAssetUrl");
const srcsetTags = ['img', 'source'];
// http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g;
const createSrcsetTransformWithOptions = (options) => {
return (node, context) => exports.transformSrcset(node, context, options);
};
exports.createSrcsetTransformWithOptions = createSrcsetTransformWithOptions;
const transformSrcset = (node, context, options = transformAssetUrl_1.defaultAssetUrlOptions) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
if (srcsetTags.includes(node.tag) && node.props.length) {
node.props.forEach((attr, index) => {
if (attr.name === 'srcset' && attr.type === compiler_core_1.NodeTypes.ATTRIBUTE) {
if (!attr.value)
return;
const value = attr.value.content;
if (!value)
return;
const imageCandidates = value
.split(',')
.map((s) => {
// The attribute value arrives here with all whitespace, except
// normal spaces, represented by escape sequences
const [url, descriptor] = s
.replace(escapedSpaceCharacters, ' ')
.trim()
.split(' ', 2);
return { url, descriptor };
});
// data urls contains comma after the encoding so we need to re-merge
// them
for (let i = 0; i < imageCandidates.length; i++) {
const { url } = imageCandidates[i];
if ((0, templateUtils_1.isDataUrl)(url)) {
imageCandidates[i + 1].url =
url + ',' + imageCandidates[i + 1].url;
imageCandidates.splice(i, 1);
}
}
const shouldProcessUrl = (url) => {
return (!(0, templateUtils_1.isExternalUrl)(url) &&
!(0, templateUtils_1.isDataUrl)(url) &&
(options.includeAbsolute || (0, templateUtils_1.isRelativeUrl)(url)));
};
// When srcset does not contain any qualified URLs, skip transforming
if (!imageCandidates.some(({ url }) => shouldProcessUrl(url))) {
return;
}
if (options.base) {
const base = options.base;
const set = [];
let needImportTransform = false;
imageCandidates.forEach((candidate) => {
let { url, descriptor } = candidate;
descriptor = descriptor ? ` ${descriptor}` : ``;
if (url[0] === '.') {
candidate.url = (path_1.default.posix || path_1.default).join(base, url);
set.push(candidate.url + descriptor);
}
else if (shouldProcessUrl(url)) {
needImportTransform = true;
}
else {
set.push(url + descriptor);
}
});
if (!needImportTransform) {
attr.value.content = set.join(', ');
return;
}
}
const compoundExpression = (0, compiler_core_1.createCompoundExpression)([], attr.loc);
imageCandidates.forEach(({ url, descriptor }, index) => {
if (shouldProcessUrl(url)) {
const { path } = (0, templateUtils_1.parseUrl)(url);
let exp;
if (path) {
const existingImportsIndex = context.imports.findIndex((i) => i.path === path);
if (existingImportsIndex > -1) {
exp = (0, compiler_core_1.createSimpleExpression)(`_imports_${existingImportsIndex}`, false, attr.loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
}
else {
exp = (0, compiler_core_1.createSimpleExpression)(`_imports_${context.imports.length}`, false, attr.loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
context.imports.push({ exp, path });
}
compoundExpression.children.push(exp);
}
}
else {
const exp = (0, compiler_core_1.createSimpleExpression)(`"${url}"`, false, attr.loc, compiler_core_1.ConstantTypes.CAN_STRINGIFY);
compoundExpression.children.push(exp);
}
const isNotLast = imageCandidates.length - 1 > index;
if (descriptor && isNotLast) {
compoundExpression.children.push(` + ' ${descriptor}, ' + `);
}
else if (descriptor) {
compoundExpression.children.push(` + ' ${descriptor}'`);
}
else if (isNotLast) {
compoundExpression.children.push(` + ', ' + `);
}
});
let exp = compoundExpression;
if (context.hoistStatic) {
exp = context.hoist(compoundExpression);
exp.constType = compiler_core_1.ConstantTypes.CAN_STRINGIFY;
}
node.props[index] = {
type: compiler_core_1.NodeTypes.DIRECTIVE,
name: 'bind',
arg: (0, compiler_core_1.createSimpleExpression)('srcset', true, attr.loc),
exp,
modifiers: [],
loc: attr.loc,
};
}
});
}
}
};
exports.transformSrcset = transformSrcset;
@@ -0,0 +1,2 @@
export declare function warnOnce(msg: string): void;
export declare function warn(msg: string): void;
@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.warn = exports.warnOnce = void 0;
const hasWarned = {};
function warnOnce(msg) {
const isNodeProd = typeof process !== 'undefined' && process.env.NODE_ENV === 'production';
if (!isNodeProd && !hasWarned[msg]) {
hasWarned[msg] = true;
warn(msg);
}
}
exports.warnOnce = warnOnce;
function warn(msg) {
console.warn(`\x1b[1m\x1b[33m[@vue/compiler-sfc]\x1b[0m\x1b[33m ${msg}\x1b[0m\n`);
}
exports.warn = warn;
@@ -0,0 +1,39 @@
import type { SFCScriptCompileOptions, SFCStyleCompileOptions, SFCTemplateCompileOptions } from '@vue/compiler-sfc';
import type * as _compiler from '@vue/compiler-sfc';
export interface Options {
include?: string | RegExp | (string | RegExp)[];
exclude?: string | RegExp | (string | RegExp)[];
isProduction?: boolean;
script?: Partial<Pick<SFCScriptCompileOptions, 'babelParserPlugins'>> & {
/**
* @deprecated defineModel is now a stable feature and always enabled if
* using Vue 3.4 or above.
*/
defineModel?: boolean;
};
template?: Partial<Pick<SFCTemplateCompileOptions, 'compiler' | 'compilerOptions' | 'preprocessOptions' | 'preprocessCustomRequire' | 'transformAssetUrls'>>;
style?: Partial<Pick<SFCStyleCompileOptions, 'trim'>>;
/**
* Transform Vue SFCs into custom elements.
* - `true`: all `*.vue` imports are converted into custom elements
* - `string | RegExp`: matched files are converted into custom elements
*
* @default /\.ce\.vue$/
*/
customElement?: boolean | string | RegExp | (string | RegExp)[];
/**
* Use custom compiler-sfc instance. Can be used to force a specific version.
*/
compiler?: typeof _compiler;
}
export interface ResolvedOptions extends Options {
compiler?: typeof _compiler;
root: string;
sourceMap: boolean;
cssDevSourcemap?: boolean;
targetLanguage?: 'kotlin';
className?: string;
classNamePrefix?: string;
componentType: 'app' | 'page' | 'component';
genDefaultAs?: string;
}
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
import type { SFCDescriptor } from '@vue/compiler-sfc';
import type { SourceMapInput, TransformPluginContext } from 'rollup';
import type { ResolvedOptions } from './index';
export declare function transformMain(code: string, filename: string, options: ResolvedOptions, pluginContext?: TransformPluginContext): Promise<{
code: string;
map: SourceMapInput;
errors: (SyntaxError | import("@vue/compiler-core").CompilerError)[];
uts: string;
descriptor: SFCDescriptor;
} | null>;
@@ -0,0 +1,289 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformMain = void 0;
const path_1 = __importDefault(require("path"));
const source_map_js_1 = require("source-map-js");
const trace_mapping_1 = require("@jridgewell/trace-mapping");
const gen_mapping_1 = require("@jridgewell/gen-mapping");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const descriptorCache_1 = require("../descriptorCache");
const script_1 = require("./script");
const utils_1 = require("../../utils");
const script_2 = require("../code/script");
const normalScript_1 = require("./compiler/script/normalScript");
async function transformMain(code, filename, options, pluginContext // 该 transformMain 方法被vuejs-core使用,编译框架内置组件了,此时不会传入pluginContext
) {
const compiler = options.compiler || require('@vue/compiler-sfc');
const { descriptor, errors } = (0, descriptorCache_1.createDescriptor)(filename, code, {
...options,
compiler,
});
const relativeFilename = descriptor.relativeFilename;
let easyComInstance = '';
if (options.genDefaultAs) {
const imports = (0, uni_cli_shared_1.getUTSEasyComAutoImports)()['@/' + relativeFilename];
if (imports && imports.length === 1) {
easyComInstance = imports[0][1];
}
}
if (errors.length) {
if (pluginContext) {
errors.forEach((error) => pluginContext.error((0, uni_cli_shared_1.createRollupError)('', filename, error, code)));
}
else {
console.error(errors);
}
return null;
}
const className = process.env.UNI_COMPILE_TARGET === 'ext-api'
? // components/map/map.vue => UniMapRender
(0, uni_cli_shared_1.genUTSClassName)(path_1.default.basename(filename), options.classNamePrefix)
: (0, uni_cli_shared_1.genUTSClassName)(relativeFilename, options.classNamePrefix);
// script
const scriptOptions = {
...options,
className,
};
let { code: scriptCode, map: scriptMap, bindingMetadata, } = await genScriptCode(descriptor, scriptOptions);
let templatePreambleCode = '';
let templateCode = '';
let templateMap = undefined;
if (options.componentType !== 'app') {
// template
const isInline = !!descriptor.scriptSetup;
if (!isInline) {
const { code, map, preamble } = (0, normalScript_1.processTemplate)(descriptor, {
relativeFilename,
bindingMetadata: bindingMetadata,
rootDir: options.root,
className,
}, pluginContext);
templateCode = code;
templateMap = map;
templatePreambleCode = preamble || '';
}
}
// styles
const stylesCode = await genStyleCode(descriptor, pluginContext);
const utsOutput = [
scriptCode || (0, script_2.genDefaultScriptCode)(options.genDefaultAs),
templateCode,
easyComInstance
? `export type ${easyComInstance} = InstanceType<typeof __sfc__>;`
: '',
`/*${className}Styles*/\n`,
];
if (templatePreambleCode) {
utsOutput.push(templatePreambleCode);
}
let resolvedMap = undefined;
if (options.sourceMap) {
if (scriptMap && templateMap) {
// if the template is inlined into the main module (indicated by the presence
// of templateMap), we need to concatenate the two source maps.
const gen = (0, gen_mapping_1.fromMap)(
// version property of result.map is declared as string
// but actually it is `3`
scriptMap);
const tracer = new trace_mapping_1.TraceMap(
// same above
templateMap);
const offset = (scriptCode.match(/\r?\n/g)?.length ?? 0) + 1;
(0, trace_mapping_1.eachMapping)(tracer, (m) => {
if (m.source == null)
return;
(0, gen_mapping_1.addMapping)(gen, {
source: m.source,
original: { line: m.originalLine, column: m.originalColumn },
generated: {
line: m.generatedLine + offset,
column: m.generatedColumn,
},
});
});
// same above
resolvedMap = (0, gen_mapping_1.toEncodedMap)(gen);
// if this is a template only update, we will be reusing a cached version
// of the main module compile result, which has outdated sourcesContent.
// resolvedMap.sourcesContent = templateMap.sourcesContent
}
else {
// if one of `scriptMap` and `templateMap` is empty, use the other one
resolvedMap = scriptMap ?? templateMap;
}
}
// handle TS transpilation
let utsCode = utsOutput.filter(Boolean).join('\n');
const jsCodes = [templatePreambleCode];
// 处理自动导入(主要是easyCom的组件类型)
const { matchedImports } = await (0, utils_1.detectAutoImports)(utsCode, descriptor.filename, easyComInstance ? [easyComInstance] : []);
if (matchedImports.length) {
const autoImportCode = (0, utils_1.genAutoImportsCode)(matchedImports);
if (autoImportCode) {
utsCode += '\n' + autoImportCode;
// 给 script 增加自动导入,让下边的 jsCode 可以 parse 到
scriptCode += '\n' + autoImportCode;
}
}
if (resolvedMap && pluginContext) {
pluginContext.emitFile({
type: 'asset',
fileName: (0, uni_cli_shared_1.normalizeEmitAssetFileName)(relativeFilename) + '.map',
source: JSON.stringify(resolvedMap),
});
if (process.env.UNI_APP_X_TSC !== 'true') {
utsCode += `
//# sourceMappingURL=${path_1.default.basename((0, uni_cli_shared_1.normalizeEmitAssetFileName)(relativeFilename))}.map`;
}
}
if (scriptCode) {
jsCodes.push(await (0, utils_1.parseImports)(scriptCode, resolvedMap && pluginContext
? createTryResolve(filename, pluginContext.resolve, resolvedMap,
// 仅需要再解析script中的importtemplate上边已经加入了
(source) => source.includes('/.uvue/') || source.includes('/.tsc/'))
: undefined));
pluginContext?.emitFile({
type: 'asset',
fileName: (0, uni_cli_shared_1.normalizeEmitAssetFileName)(relativeFilename),
source: utsCode,
});
}
if (stylesCode) {
jsCodes.push(stylesCode);
}
jsCodes.push(`export default "${className}"
${easyComInstance ? `export const ${easyComInstance} = {}` : ''}`);
let jsCode = jsCodes.filter(Boolean).join('\n');
return {
code: processJsCodeImport(jsCode),
map: {
mappings: '',
},
// 这些都是 vuejs-core 需要的
errors,
uts: utsCode,
descriptor,
};
}
exports.transformMain = transformMain;
function processJsCodeImport(jsCode) {
if (jsCode.includes('@/node-modules/@dcloudio/uni-components/lib-x')) {
return jsCode.replaceAll('@/node-modules/@dcloudio/uni-components/lib-x', (0, uni_cli_shared_1.normalizePath)((0, uni_cli_shared_1.resolveComponentsLibPath)()));
}
return jsCode;
}
async function genScriptCode(descriptor, options) {
let scriptCode = (0, script_2.genDefaultScriptCode)(options.genDefaultAs);
let map;
const script = (0, script_1.resolveScript)(descriptor, options);
if (script) {
scriptCode = script.content;
map = script.map;
}
return {
code: scriptCode,
map,
bindingMetadata: script?.bindings,
};
}
async function genStyleCode(descriptor, pluginContext) {
let stylesCode = ``;
if (descriptor.styles.length) {
for (let i = 0; i < descriptor.styles.length; i++) {
const style = descriptor.styles[i];
if (style.src && pluginContext) {
await linkSrcToDescriptor(style.src, descriptor, pluginContext);
}
const src = style.src || descriptor.filename;
// do not include module in default query, since we use it to indicate
// that the module needs to export the modules json
const attrsQuery = attrsToQuery(style.attrs, 'css');
style.scoped = false; // fixed by xxxxxx 强制不scoped
const srcQuery = style.src
? style.scoped
? `&src=${descriptor.id}`
: '&src=true'
: '';
const directQuery = ``;
const scopedQuery = style.scoped ? `&scoped=${descriptor.id}` : ``;
const query = `?vue&type=style&index=${i}${srcQuery}${directQuery}${scopedQuery}`;
const styleRequest = src + query + attrsQuery;
stylesCode += `\nimport ${JSON.stringify(styleRequest)}`;
}
// TODO SSR critical CSS collection
}
return stylesCode;
}
/**
* For blocks with src imports, it is important to link the imported file
* with its owner SFC descriptor so that we can get the information about
* the owner SFC when compiling that file in the transform phase.
*/
async function linkSrcToDescriptor(src, descriptor, pluginContext) {
const srcFile = (await pluginContext.resolve(src, descriptor.filename))?.id || src;
// #1812 if the src points to a dep file, the resolved id may contain a
// version query.
(0, descriptorCache_1.setSrcDescriptor)(srcFile.replace(/\?.*$/, ''), descriptor);
}
// these are built-in query parameters so should be ignored
// if the user happen to add them as attrs
const ignoreList = [
'id',
'index',
'src',
'type',
'lang',
'module',
'scoped',
'generic',
];
function attrsToQuery(attrs, langFallback, forceLangFallback = false) {
let query = ``;
for (const name in attrs) {
const value = attrs[name];
if (!ignoreList.includes(name)) {
query += `&${encodeURIComponent(name)}${value ? `=${encodeURIComponent(value)}` : ``}`;
}
}
if (langFallback || attrs.lang) {
query +=
`lang` in attrs
? forceLangFallback
? `&lang.${langFallback}`
: `&lang.${attrs.lang}`
: `&lang.${langFallback}`;
}
return query;
}
function createTryResolve(importer, resolve, resolvedMap, ignore) {
return async (source, code, { ss, se }) => {
if (ignore && ignore(source)) {
return false;
}
const resolved = await (0, utils_1.wrapResolve)(resolve)(source, importer);
if (!resolved) {
const { start, end } = (0, uni_cli_shared_1.offsetToStartAndEnd)(code, ss, se);
const consumer = new source_map_js_1.SourceMapConsumer(resolvedMap);
const startPos = consumer.originalPositionFor({
line: start.line,
column: start.column,
});
if (startPos.line != null &&
startPos.column != null &&
startPos.source != null) {
const endPos = consumer.originalPositionFor({
line: end.line,
column: end.column,
});
if (endPos.line != null && endPos.column != null) {
startPos.column = startPos.column + 1;
endPos.column = endPos.column + 1;
throw (0, utils_1.createResolveError)(consumer.sourceContentFor(startPos.source) ?? '', (0, uni_cli_shared_1.createResolveErrorMsg)(source, importer), startPos, endPos);
}
}
}
};
}
@@ -0,0 +1,8 @@
import type { SFCDescriptor, SFCScriptBlock } from 'vue/compiler-sfc';
import type { ResolvedOptions } from '.';
export declare function invalidateScript(filename: string): void;
export declare function getResolvedScript(descriptor: SFCDescriptor): SFCScriptBlock | null | undefined;
export declare function setResolvedScript(descriptor: SFCDescriptor, script: SFCScriptBlock): void;
export declare function isUseInlineTemplate(descriptor: SFCDescriptor, isProd: boolean): boolean;
export declare const scriptIdentifier = "__sfc__";
export declare function resolveScript(descriptor: SFCDescriptor, options: ResolvedOptions): SFCScriptBlock | null;
@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveScript = exports.scriptIdentifier = exports.isUseInlineTemplate = exports.setResolvedScript = exports.getResolvedScript = exports.invalidateScript = void 0;
const template_1 = require("./template");
const descriptorCache_1 = require("../descriptorCache");
const compileScript_1 = require("./compiler/compileScript");
const scriptCache = new WeakMap();
function invalidateScript(filename) {
const desc = descriptorCache_1.cache.get(filename);
if (desc) {
scriptCache.delete(desc);
}
}
exports.invalidateScript = invalidateScript;
function getResolvedScript(descriptor) {
return scriptCache.get(descriptor);
}
exports.getResolvedScript = getResolvedScript;
function setResolvedScript(descriptor, script) {
scriptCache.set(descriptor, script);
}
exports.setResolvedScript = setResolvedScript;
// Check if we can use compile template as inlined render function
// inside <script setup>. This can only be done for build because
// inlined template cannot be individually hot updated.
function isUseInlineTemplate(descriptor, isProd) {
return isProd && !!descriptor.scriptSetup && !descriptor.template?.src;
}
exports.isUseInlineTemplate = isUseInlineTemplate;
exports.scriptIdentifier = `__sfc__`;
function resolveScript(descriptor, options) {
if (!descriptor.script && !descriptor.scriptSetup) {
return null;
}
const cached = getResolvedScript(descriptor);
if (cached) {
return cached;
}
let resolved = null;
resolved = (0, compileScript_1.compileScript)(descriptor, {
...options.script,
className: options.className || '',
root: options.root,
id: descriptor.id,
isProd: options.isProduction,
inlineTemplate: true,
hoistStatic: false,
templateOptions: (0, template_1.resolveTemplateCompilerOptions)(descriptor, options),
sourceMap: options.sourceMap,
defineModel: true,
componentType: options.componentType,
genDefaultAs: exports.scriptIdentifier,
});
setResolvedScript(descriptor, resolved);
return resolved;
}
exports.resolveScript = resolveScript;
@@ -0,0 +1,17 @@
import type { TransformPluginContext } from 'rollup';
import type { BindingMetadata, SFCDescriptor, SFCTemplateCompileOptions } from 'vue/compiler-sfc';
import type { ResolvedOptions } from '.';
import type { TemplateCompilerOptions } from '../compiler/options';
export declare function resolveGenTemplateCodeOptions(relativeFileName: string, code: string, descriptor: SFCDescriptor, options: {
mode: 'module' | 'default';
inline: boolean;
rootDir: string;
className: string;
sourceMap: boolean;
bindingMetadata?: BindingMetadata;
preprocessLang?: string;
preprocessOptions?: any;
}, pluginContext?: TransformPluginContext): TemplateCompilerOptions & {
genDefaultAs?: string;
};
export declare function resolveTemplateCompilerOptions(descriptor: SFCDescriptor, options: ResolvedOptions): Omit<SFCTemplateCompileOptions, 'source'> | undefined;
@@ -0,0 +1,149 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveTemplateCompilerOptions = exports.resolveGenTemplateCodeOptions = void 0;
const path_1 = __importDefault(require("path"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const script_1 = require("./script");
const utils_1 = require("../../utils");
function resolveGenTemplateCodeOptions(relativeFileName, code, descriptor, options, pluginContext) {
const block = descriptor.template;
if (!block) {
return {
genDefaultAs: script_1.scriptIdentifier,
...options,
filename: relativeFileName,
};
}
const inputRoot = (0, uni_cli_shared_1.normalizePath)(options.rootDir);
const templateStartLine = descriptor.template?.loc.start.line ?? 0;
let preprocessOptions = block.lang && options.preprocessOptions;
if (block.lang === 'pug') {
preprocessOptions = {
doctype: 'html',
...preprocessOptions,
};
}
return {
genDefaultAs: script_1.scriptIdentifier,
...options,
filename: relativeFileName,
inMap: descriptor.template?.map,
preprocessLang: block.lang === 'html' ? undefined : block.lang,
preprocessOptions,
inline: !!descriptor.scriptSetup,
matchEasyCom: (tag, uts) => {
const source = (0, uni_cli_shared_1.matchEasycom)(tag);
if (uts && source) {
if (source.startsWith(inputRoot)) {
return '@/' + (0, uni_cli_shared_1.normalizePath)(path_1.default.relative(inputRoot, source));
}
return (0, utils_1.parseUTSImportFilename)(source);
}
return source;
},
onWarn(warning) {
if (pluginContext) {
pluginContext.warn((0, uni_cli_shared_1.createRollupError)('', path_1.default.resolve(options.rootDir, relativeFileName), warning, code));
}
else {
onTemplateLog('warn', warning, code, relativeFileName, templateStartLine);
}
},
onError(error) {
if (pluginContext) {
pluginContext.error((0, uni_cli_shared_1.createRollupError)('', path_1.default.resolve(options.rootDir, relativeFileName), error, code));
}
else {
onTemplateLog('error', error, code, relativeFileName, templateStartLine);
}
},
parseUTSComponent: uni_cli_shared_1.parseUTSComponent,
};
}
exports.resolveGenTemplateCodeOptions = resolveGenTemplateCodeOptions;
function onTemplateLog(type, error, code, relativeFileName, templateStartLine) {
console.error(type + ': ' + error.message);
if (error.loc) {
const start = error.loc.start;
console.log('at ' +
relativeFileName +
':' +
(start.line + templateStartLine - 1) +
':' +
(start.column - 1));
console.log((0, uni_cli_shared_1.generateCodeFrameColumns)(code, error.loc));
}
}
function resolveTemplateCompilerOptions(descriptor, options) {
const block = descriptor.template;
if (!block) {
return;
}
const resolvedScript = (0, script_1.getResolvedScript)(descriptor);
const hasScoped = descriptor.styles.some((s) => s.scoped);
const { id, filename, cssVars } = descriptor;
let transformAssetUrls = options.template?.transformAssetUrls;
// compiler-sfc should export `AssetURLOptions`
let assetUrlOptions; //: AssetURLOptions | undefined
if (transformAssetUrls !== false) {
// build: force all asset urls into import requests so that they go through
// the assets plugin for asset registration
assetUrlOptions = {
includeAbsolute: true,
};
}
if (transformAssetUrls && typeof transformAssetUrls === 'object') {
// presence of array fields means this is raw tags config
if (Object.values(transformAssetUrls).some((val) => Array.isArray(val))) {
transformAssetUrls = {
...assetUrlOptions,
tags: transformAssetUrls,
};
}
else {
transformAssetUrls = { ...assetUrlOptions, ...transformAssetUrls };
}
}
else {
transformAssetUrls = assetUrlOptions;
}
let preprocessOptions = block.lang && options.template?.preprocessOptions;
if (block.lang === 'pug') {
preprocessOptions = {
doctype: 'html',
...preprocessOptions,
};
}
// if using TS, support TS syntax in template expressions
const expressionPlugins = options.template?.compilerOptions?.expressionPlugins || [];
const lang = descriptor.scriptSetup?.lang || descriptor.script?.lang;
if (lang && /tsx?$/.test(lang) && !expressionPlugins.includes('typescript')) {
expressionPlugins.push('typescript');
}
return {
...options.template,
id,
// TODO remove ignore when dep is updated to 3.4
ast: descriptor.template?.ast,
filename,
scoped: hasScoped,
slotted: descriptor.slotted,
isProd: options.isProduction,
inMap: block.src ? undefined : block.map,
ssrCssVars: cssVars,
transformAssetUrls,
preprocessLang: block.lang === 'html' ? undefined : block.lang,
preprocessOptions,
compilerOptions: {
...options.template?.compilerOptions,
scopeId: hasScoped ? `data-v-${id}` : undefined,
bindingMetadata: resolvedScript ? resolvedScript.bindings : undefined,
expressionPlugins,
sourceMap: options.sourceMap,
},
};
}
exports.resolveTemplateCompilerOptions = resolveTemplateCompilerOptions;