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
+3
View File
@@ -0,0 +1,3 @@
import type { Plugin } from 'vite';
export declare function uniAppCssPrePlugin(): Plugin;
export declare function uniAppCssPlugin(): Plugin;
+139
View File
@@ -0,0 +1,139 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniAppCssPlugin = exports.uniAppCssPrePlugin = void 0;
const path_1 = __importDefault(require("path"));
const picocolors_1 = __importDefault(require("picocolors"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const uni_nvue_styler_1 = require("@dcloudio/uni-nvue-styler");
const descriptorCache_1 = require("./uvue/descriptorCache");
const utils_1 = require("./utils");
function uniAppCssPrePlugin() {
const name = 'uni:app-uvue-css-pre';
const descriptorOptions = {
...(0, descriptorCache_1.getResolvedOptions)(),
sourceMap: false,
};
const mainPath = (0, uni_cli_shared_1.resolveMainPathOnce)(process.env.UNI_INPUT_DIR);
return {
name,
// 需要提前,因为unocss会在configResolved读取vite:css-post插件
// 所以需要在它之前做替换
enforce: 'pre',
apply: 'build',
configResolved(config) {
(0, uni_cli_shared_1.removePlugins)(['vite:css', 'vite:css-post'], config);
const uvueCssPostPlugin = (0, uni_cli_shared_1.cssPostPlugin)(config, {
isJsCode: true,
platform: process.env.UNI_PLATFORM,
includeComponentCss: false,
chunkCssFilename(id) {
const { filename } = (0, uni_cli_shared_1.parseVueRequest)(id);
if (filename === mainPath) {
// 合并到App
return `App.uvue.style.uts`;
}
if ((0, utils_1.isVue)(filename)) {
return (0, uni_cli_shared_1.normalizeNodeModules)((path_1.default.isAbsolute(filename)
? path_1.default.relative(process.env.UNI_INPUT_DIR, filename)
: filename) + '.style.uts');
}
},
async chunkCssCode(filename, cssCode) {
cssCode = (0, uni_cli_shared_1.parseAssets)(config, cssCode);
const { code, messages } = await (0, uni_nvue_styler_1.parse)(cssCode, {
filename,
logLevel: 'ERROR',
mapOf: 'utsMapOf',
chunk: 100,
type: 'uvue',
platform: process.env.UNI_UTS_PLATFORM,
trim: true,
});
messages.forEach((message) => {
if (message.type === 'error') {
let msg = `[plugin:uni:app-uvue-css] ${message.text}`;
if (message.line && message.column) {
msg += `\n${(0, uni_cli_shared_1.generateCodeFrame)(cssCode, {
line: message.line,
column: message.column,
}).replace(/\t/g, ' ')}`;
}
msg += `\n${(0, uni_cli_shared_1.formatAtFilename)(filename)}`;
config.logger.error(picocolors_1.default.red(msg));
}
});
const fileName = filename.replace('.style.uts', '');
const className = process.env.UNI_COMPILE_TARGET === 'ext-api'
? // components/map/map.vue => UniMap
(0, uni_cli_shared_1.genUTSClassName)(path_1.default.basename(fileName), descriptorOptions.classNamePrefix)
: (0, uni_cli_shared_1.genUTSClassName)(fileName, descriptorOptions.classNamePrefix);
return `export const ${className}Styles = ${code}`;
},
});
// 增加 css plugins
// TODO 加密插件
(0, uni_cli_shared_1.insertBeforePlugin)((0, uni_cli_shared_1.cssPlugin)(config, {
isAndroidX: true,
getDescriptor: (filename) => {
return (0, descriptorCache_1.getDescriptor)(filename, descriptorOptions, false);
},
}), name, config);
const plugins = config.plugins;
const index = plugins.findIndex((p) => p.name === 'uni:app-uvue');
plugins.splice(index, 0, uvueCssPostPlugin);
},
};
}
exports.uniAppCssPrePlugin = uniAppCssPrePlugin;
function uniAppCssPlugin() {
let resolvedConfig;
return {
name: 'uni:app-uvue-css',
apply: 'build',
configResolved(config) {
resolvedConfig = config;
},
async transform(source, filename) {
if (!uni_cli_shared_1.cssLangRE.test(filename) || uni_cli_shared_1.commonjsProxyRE.test(filename)) {
return;
}
if (filename.endsWith('__uno.css')) {
return;
}
if (source.includes('#endif')) {
source = (0, uni_cli_shared_1.preUVueCss)(source);
}
source = (0, uni_cli_shared_1.parseAssets)(resolvedConfig, source);
// 仅做校验使用
const { messages } = await (0, uni_nvue_styler_1.parse)(source, {
filename,
logLevel: 'WARNING',
map: true,
ts: true,
noCode: true,
type: 'uvue',
platform: process.env.UNI_UTS_PLATFORM,
});
messages.forEach((message) => {
if (message.type === 'warning') {
// 拆分成多行,第一行输出信息(有颜色),后续输出错误代码+文件行号
resolvedConfig.logger.warn(picocolors_1.default.yellow(`[plugin:uni:app-uvue-css] ${message.text}`));
let msg = '';
if (message.line && message.column) {
msg += `\n${(0, uni_cli_shared_1.generateCodeFrame)(source, {
line: message.line,
column: message.column,
}).replace(/\t/g, ' ')}\n`;
}
msg += `${(0, uni_cli_shared_1.formatAtFilename)(filename)}`;
resolvedConfig.logger.warn(msg);
}
});
return { code: source };
},
};
}
exports.uniAppCssPlugin = uniAppCssPlugin;
+1
View File
@@ -0,0 +1 @@
export declare function init(): import("vite").Plugin<any>[];
+45
View File
@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const pre_1 = require("./pre");
const plugin_1 = require("./plugin");
const css_1 = require("./css");
const mainUTS_1 = require("./mainUTS");
const manifestJson_1 = require("./manifestJson");
const pagesJson_1 = require("./pagesJson");
const uvue_1 = require("./uvue");
const unicloud_1 = require("./unicloud");
function init() {
return [
(0, css_1.uniAppCssPrePlugin)(),
...((0, uni_cli_shared_1.isNormalCompileTarget)() ? [(0, uni_cli_shared_1.uniDecryptUniModulesPlugin)()] : []),
(0, pre_1.uniPrePlugin)(),
...((0, uni_cli_shared_1.isNormalCompileTarget)()
? [
(0, uni_cli_shared_1.uniUTSAppUniModulesPlugin)({
x: true,
isSingleThread: process.env.UNI_APP_X_SINGLE_THREAD !== 'false',
extApis: (0, uni_cli_shared_1.parseUniExtApiNamespacesOnce)(process.env.UNI_UTS_PLATFORM, process.env.UNI_UTS_TARGET_LANGUAGE),
}),
]
: []),
(0, plugin_1.uniAppPlugin)(),
...(process.env.UNI_COMPILE_TARGET === 'ext-api'
? [(0, uni_cli_shared_1.uniUniModulesExtApiPlugin)()]
: process.env.UNI_COMPILE_TARGET === 'uni_modules'
? [(0, uni_cli_shared_1.uniEncryptUniModulesPlugin)()]
: [
// 需要放到 uniAppPlugin 之后(TSC模式无需),让 uniAppPlugin 先 emit 出真实的 main.uts,然后 MainPlugin 再返回仅包含 import 的 js code
(0, mainUTS_1.uniAppMainPlugin)(),
(0, manifestJson_1.uniAppManifestPlugin)(),
(0, pagesJson_1.uniAppPagesPlugin)(),
]),
(0, css_1.uniAppCssPlugin)(),
// 解决所有的src引入
(0, uni_cli_shared_1.uniViteSfcSrcImportPlugin)({ onlyVue: false }),
(0, uvue_1.uniAppUVuePlugin)(),
(0, unicloud_1.uniCloudPlugin)(),
];
}
exports.init = init;
+2
View File
@@ -0,0 +1,2 @@
import type { Plugin } from 'vite';
export declare function uniAppMainPlugin(): Plugin;
+25
View File
@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniAppMainPlugin = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
function uniAppMainPlugin() {
const mainUTS = (0, uni_cli_shared_1.resolveMainPathOnce)(process.env.UNI_INPUT_DIR);
return {
name: 'uni:app-main',
apply: 'build',
async transform(code, id) {
if ((0, uni_cli_shared_1.normalizePath)(id) === mainUTS) {
code = await (0, utils_1.parseImports)(code, (0, utils_1.createTryResolve)(id, this.resolve.bind(this)));
return {
code: `import './${uni_cli_shared_1.MANIFEST_JSON_UTS}'
import './${uni_cli_shared_1.PAGES_JSON_UTS}'
${code}
`,
map: null,
};
}
},
};
}
exports.uniAppMainPlugin = uniAppMainPlugin;
@@ -0,0 +1,3 @@
import type { Plugin } from 'vite';
export declare function getOutputManifestJson(): Record<string, any> | undefined;
export declare function uniAppManifestPlugin(): Plugin;
@@ -0,0 +1,97 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniAppManifestPlugin = exports.getOutputManifestJson = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
const utils_2 = require("../utils");
let outputManifestJson = undefined;
function getOutputManifestJson() {
return outputManifestJson;
}
exports.getOutputManifestJson = getOutputManifestJson;
function uniAppManifestPlugin() {
const manifestJsonPath = path_1.default.resolve(process.env.UNI_INPUT_DIR, 'manifest.json');
const manifestJsonUTSPath = path_1.default.resolve(process.env.UNI_INPUT_DIR, uni_cli_shared_1.MANIFEST_JSON_UTS);
let manifestJson = {};
return {
name: 'uni:app-manifest',
apply: 'build',
resolveId(id) {
if ((0, utils_2.isManifest)(id)) {
return manifestJsonUTSPath;
}
},
load(id) {
if ((0, utils_2.isManifest)(id)) {
return fs_extra_1.default.readFileSync(manifestJsonPath, 'utf8');
}
},
transform(code, id) {
if ((0, utils_2.isManifest)(id)) {
this.addWatchFile(path_1.default.resolve(process.env.UNI_INPUT_DIR, 'manifest.json'));
manifestJson = (0, uni_cli_shared_1.parseJson)(code);
return `export default 'manifest.json'`;
}
},
generateBundle(_, bundle) {
if (bundle[(0, utils_1.ENTRY_FILENAME)()]) {
const asset = bundle[(0, utils_1.ENTRY_FILENAME)()];
const singleThreadCode = manifestJson?.['uni-app-x']?.['singleThread'] === false
? `override singleThread = false`
: '';
const flexDir = (0, uni_cli_shared_1.parseUniXFlexDirection)(manifestJson);
const flexDirCode = flexDir !== 'column' ? `override flexDirection = "${flexDir}"` : '';
const splashScreen = (0, uni_cli_shared_1.parseUniXSplashScreen)(manifestJson);
const splashScreenCode = splashScreen && Object.keys(splashScreen).length > 0
? `override splashScreen: Map<string, any> | null = ${(0, utils_1.stringifyMap)(splashScreen)}`
: '';
const uniStatistics = (0, uni_cli_shared_1.parseUniXUniStatistics)(manifestJson);
const uniStatisticsCode = uniStatistics && Object.keys(uniStatistics).length > 0
? `override uniStatistics: UTSJSONObject | null = ${JSON.stringify(uniStatistics)}`
: '';
const hasAppDefaultAppTheme = (0, uni_cli_shared_1.validateThemeValue)(manifestJson.app?.defaultAppTheme);
const hasDefaultAppTheme = (0, uni_cli_shared_1.validateThemeValue)(manifestJson.defaultAppTheme);
const defaultAppThemeCode = hasAppDefaultAppTheme
? `override defaultAppTheme: string = "${manifestJson.app.defaultAppTheme}"`
: hasDefaultAppTheme
? `override defaultAppTheme: string = "${manifestJson.defaultAppTheme}"`
: '';
const codes = [
singleThreadCode,
flexDirCode,
splashScreenCode,
defaultAppThemeCode,
uniStatisticsCode,
]
.filter(Boolean)
.join('\n');
asset.source =
asset.source +
`
export class UniAppConfig extends io.dcloud.uniapp.appframe.AppConfig {
override name: string = "${manifestJson.name || ''}"
override appid: string = "${manifestJson.appid || ''}"
override versionName: string = "${manifestJson.versionName || ''}"
override versionCode: string = "${manifestJson.versionCode || ''}"
override uniCompilerVersion: string = "${process.env.UNI_COMPILER_VERSION || ''}"
${codes}
constructor() { super() }
}
`;
}
},
writeBundle() {
outputManifestJson = (0, utils_2.normalizeManifestJson)(manifestJson);
if (process.env.NODE_ENV !== 'production') {
// 发行模式下,需要等解析ext-api模块
fs_extra_1.default.outputFileSync(path_1.default.resolve(process.env.UNI_OUTPUT_DIR, 'manifest.json'), JSON.stringify(outputManifestJson, null, 2));
}
},
};
}
exports.uniAppManifestPlugin = uniAppManifestPlugin;
@@ -0,0 +1,2 @@
import type { Plugin } from 'vite';
export declare function uniAppPagesPlugin(): Plugin;
+163
View File
@@ -0,0 +1,163 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniAppPagesPlugin = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
const utils_2 = require("../utils");
function uniAppPagesPlugin() {
const pagesJsonPath = path_1.default.resolve(process.env.UNI_INPUT_DIR, 'pages.json');
const pagesJsonUTSPath = path_1.default.resolve(process.env.UNI_INPUT_DIR, uni_cli_shared_1.PAGES_JSON_UTS);
let imports = [];
let routes = [];
let globalStyle = 'new Map()';
let tabBar = 'null';
let launchPage = 'null';
let conditionUrl = '';
let uniIdRouter = 'new Map()';
let themeConfig = '';
const codes = [];
return {
name: 'uni:app-pages',
apply: 'build',
resolveId(id) {
if ((0, utils_2.isPages)(id)) {
return pagesJsonUTSPath;
}
},
load(id) {
if ((0, utils_2.isPages)(id)) {
return fs_extra_1.default.readFileSync(pagesJsonPath, 'utf8');
}
},
transform(code, id) {
if ((0, utils_2.isPages)(id)) {
this.addWatchFile(path_1.default.resolve(process.env.UNI_INPUT_DIR, 'pages.json'));
this.addWatchFile(path_1.default.resolve(process.env.UNI_INPUT_DIR, 'theme.json'));
let pagesJson = {
pages: [],
globalStyle: {
navigationBar: {},
},
};
// 调整换行符,确保 parseTree 的loc正确
code = code.replace(/\r\n/g, '\n');
try {
pagesJson = (0, uni_cli_shared_1.normalizeUniAppXAppPagesJson)(code);
}
catch (err) {
if (err.loc) {
const error = (0, uni_cli_shared_1.createRollupError)('uni:app-pages', pagesJsonPath, err, code);
this.error(error);
}
else {
throw err;
}
}
imports = [];
routes = [];
process.env.UNI_APP_X_PAGE_COUNT = pagesJson.pages.length + '';
(0, utils_2.setGlobalPageOrientation)(pagesJson.globalStyle?.pageOrientation || '');
pagesJson.pages.forEach((page, index) => {
const className = (0, uni_cli_shared_1.genUTSClassName)(page.path);
let isQuit = index === 0;
imports.push(page.path);
routes.push(`{ path: "${page.path}", component: ${className}Class, meta: { isQuit: ${isQuit} } as UniPageMeta, style: ${stringifyPageStyle(page.style)}${page.needLogin === undefined
? ''
: ', needLogin: ' + page.needLogin} } as UniPageRoute`);
});
if (pagesJson.globalStyle) {
globalStyle = stringifyPageStyle(pagesJson.globalStyle);
}
if (pagesJson.tabBar) {
tabBar = (0, utils_1.stringifyMap)(pagesJson.tabBar);
}
if (pagesJson.condition) {
const conditionInfo = (0, uni_cli_shared_1.parseArguments)(pagesJson);
if (conditionInfo) {
const { path, query } = JSON.parse(conditionInfo);
conditionUrl = `${path}${query ? '?' + query : ''}`;
}
}
if (pagesJson.uniIdRouter) {
uniIdRouter = (0, utils_1.stringifyMap)(pagesJson.uniIdRouter);
}
launchPage = stringifyLaunchPage(pagesJson.pages[0]);
codes.length = 0;
// theme.json
themeConfig = readThemeJSONFileAsStringifyMap();
if (themeConfig) {
codes.push(`__uniConfig.themeConfig = ${themeConfig}`);
}
return {
code: `${imports
.map((p) => `import './${p}.uvue?type=page'`)
.join('\n')}
export default 'pages.json'`,
map: null,
};
}
},
generateBundle(_, bundle) {
if (bundle[(0, utils_1.ENTRY_FILENAME)()]) {
const asset = bundle[(0, utils_1.ENTRY_FILENAME)()];
asset.source =
asset.source +
`
${imports
.map((p) => {
const className = (0, uni_cli_shared_1.genUTSClassName)(p);
return `import ${className}Class from './${p}.uvue?type=page'`;
})
.join('\n')}
function definePageRoutes() {
${routes.map((route) => `__uniRoutes.push(${route})`).join('\n')}
}
const __uniTabBar: Map<string, any | null> | null = ${tabBar}
const __uniLaunchPage: Map<string, any | null> = ${launchPage}
function defineAppConfig(){
__uniConfig.entryPagePath = '/${imports[0]}'
__uniConfig.globalStyle = ${globalStyle}
__uniConfig.getTabBarConfig = ():Map<string, any> | null => ${tabBar}
__uniConfig.tabBar = __uniConfig.getTabBarConfig()
__uniConfig.conditionUrl = '${conditionUrl}'
__uniConfig.uniIdRouter = ${uniIdRouter}
${codes.join('\n ')}
__uniConfig.ready = true
}
`;
}
},
};
}
exports.uniAppPagesPlugin = uniAppPagesPlugin;
function stringifyLaunchPage(launchPage) {
return (0, utils_1.stringifyMap)({
url: launchPage.path,
style: launchPage.style,
}, true);
}
function stringifyPageStyle(pageStyle) {
return (0, utils_1.stringifyMap)(pageStyle);
}
// function readUniSassAsStringifyMap() {
// const uniScssPath = path.resolve(process.env.UNI_INPUT_DIR, 'uni.scss')
// let result = {}
// if (fs.existsSync(uniScssPath)) {
// const content = fs.readFileSync(uniScssPath, 'utf8')
// const parser = new ThemeSassParser()
// result = parser.parse(content)
// }
// return stringifyMap(result)
// }
function readThemeJSONFileAsStringifyMap() {
const themeJsonPath = path_1.default.resolve(process.env.UNI_INPUT_DIR, 'theme.json');
if (fs_extra_1.default.existsSync(themeJsonPath)) {
return (0, utils_1.stringifyMap)(JSON.parse(fs_extra_1.default.readFileSync(themeJsonPath, 'utf8')));
}
return '';
}
+2
View File
@@ -0,0 +1,2 @@
import { type UniVitePlugin } from '@dcloudio/uni-cli-shared';
export declare function uniAppPlugin(): UniVitePlugin;
+362
View File
@@ -0,0 +1,362 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniAppPlugin = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const shared_1 = require("@vue/shared");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
const manifestJson_1 = require("./manifestJson");
const utils_2 = require("../utils");
const uniCloudSpaceList = (0, utils_1.getUniCloudSpaceList)();
let isFirst = true;
function uniAppPlugin() {
const inputDir = process.env.UNI_INPUT_DIR;
const outputDir = process.env.UNI_OUTPUT_DIR;
// const uniModulesDir = normalizePath(path.resolve(inputDir, 'uni_modules'))
const mainUTS = (0, uni_cli_shared_1.resolveMainPathOnce)(inputDir);
const pagesJsonPath = (0, uni_cli_shared_1.normalizePath)(path_1.default.resolve(inputDir, 'pages.json'));
const uvueOutputDir = (0, uni_cli_shared_1.uvueOutDir)('app-android');
const tscOutputDir = (0, uni_cli_shared_1.tscOutDir)('app-android');
const manifestJson = (0, uni_cli_shared_1.parseManifestJsonOnce)(inputDir);
// 预留一个口子,方便切换测试
const split = manifestJson['uni-app-x']?.split;
// 开始编译时,清空输出目录
function emptyOutDir() {
// ext-api 编译时,需要同时编译多个平台,并保留多个平台的输出目录
if (process.env.UNI_COMPILE_TARGET === 'ext-api') {
return;
}
if (fs_extra_1.default.existsSync(outputDir)) {
(0, uni_cli_shared_1.emptyDir)(outputDir);
}
}
emptyOutDir();
function emptyUVueDir() {
if (fs_extra_1.default.existsSync(uvueOutputDir)) {
(0, uni_cli_shared_1.emptyDir)(uvueOutputDir);
}
}
emptyUVueDir();
function emptyTscDir() {
if (fs_extra_1.default.existsSync(tscOutputDir)) {
(0, uni_cli_shared_1.emptyDir)(tscOutputDir);
}
}
emptyTscDir();
let resolvedConfig;
const uniXKotlinCompiler = process.env.UNI_APP_X_TSC === 'true'
? (0, uni_cli_shared_1.resolveUTSCompiler)().createUniXKotlinCompilerOnce()
: null;
const changedFiles = [];
return {
name: 'uni:app-uts',
apply: 'build',
uni: (0, utils_2.createUniOptions)('android'),
config() {
return {
base: '/', // 强制 base
build: {
// 手动清理
emptyOutDir: false,
outDir: process.env.UNI_APP_X_TSC === 'true' ? tscOutputDir : uvueOutputDir,
lib: {
// 必须使用 lib 模式
fileName: 'output',
entry: (0, uni_cli_shared_1.resolveMainPathOnce)(inputDir),
formats: ['cjs'],
},
rollupOptions: {
external(source) {
if (['vue', 'vuex', 'pinia', '@dcloudio/uni-app'].includes(source)) {
return true;
}
// 相对目录
if (source.startsWith('@/') || source.startsWith('.')) {
return false;
}
if (path_1.default.isAbsolute(source)) {
return false;
}
// 'virtual:uno.css'
if (source.includes(':')) {
return false;
}
// android 系统库,三方库,iOS 的库呢?一般不包含.
if (source.includes('.')) {
return true;
}
return false;
},
output: {
chunkFileNames(chunk) {
// if (chunk.isDynamicEntry && chunk.facadeModuleId) {
// const { filename } = parseVueRequest(chunk.facadeModuleId)
// if (filename.endsWith('.nvue')) {
// return (
// removeExt(
// normalizePath(path.relative(inputDir, filename))
// ) + '.js'
// )
// }
// }
return '[name].js';
},
},
},
},
};
},
async configResolved(config) {
(0, utils_2.configResolved)(config, true);
resolvedConfig = config;
if (uniXKotlinCompiler) {
await uniXKotlinCompiler.init();
}
},
async transform(code, id) {
const { filename } = (0, uni_cli_shared_1.parseVueRequest)(id);
if (!filename.endsWith('.uts') && !filename.endsWith('.ts')) {
if (filename.endsWith('.json')) {
this.emitFile({
type: 'asset',
fileName: (0, uni_cli_shared_1.normalizeEmitAssetFileName)(normalizeFilename(id, false)),
source: code,
});
}
return;
}
// 仅处理 uts 文件
// 忽略 uni-app-uts/lib/automator/index.uts
if (!filename.includes('uni-app-uts')) {
code = (await (0, utils_1.transformAutoImport)((0, utils_1.transformUniCloudMixinDataCom)((0, uni_cli_shared_1.rewriteUniModulesConsoleExpr)(id, code)), id)).code;
const isMainUTS = (0, uni_cli_shared_1.normalizePath)(id) === mainUTS;
this.emitFile({
type: 'asset',
fileName: (0, uni_cli_shared_1.normalizeEmitAssetFileName)(normalizeFilename(id, isMainUTS)),
source: normalizeCode(code, isMainUTS),
});
}
code = await (0, utils_1.parseImports)(code, (0, utils_1.createTryResolve)(id, this.resolve.bind(this)));
return code;
},
generateBundle(_, bundle) {
if (!(0, uni_cli_shared_1.isNormalCompileTarget)()) {
return;
}
// 开发者仅在 script 中引入了 easyCom 类型,但模板里边没用到,此时额外生成一个辅助的.uvue文件
// checkUTSEasyComAutoImports(inputDir, bundle, this)
},
watchChange(fileName, change) {
if (uniXKotlinCompiler) {
// watcher && watcher.watch(3000)
fileName = (0, uni_cli_shared_1.normalizePath)(fileName);
if (fileName === pagesJsonPath) {
// pages.json 被注入了main.uts,需要触发main.uts的重新编译
changedFiles.push({
fileName: (0, uni_cli_shared_1.normalizePath)(mainUTS),
event: change.event,
});
}
else {
// 主工程可能引入uni_modules中的文件
// if (fileName.startsWith(uniModulesDir)) {
// // 忽略uni_modules uts原生插件中的文件
// const plugin = fileName
// .slice(uniModulesDir.length + 1)
// .split('/')[0]
// if (getCurrentCompiledUTSPlugins().has(plugin)) {
// return
// }
// }
const depMap = (0, uni_cli_shared_1.getCssDepMap)();
if (depMap.has(fileName)) {
for (const id of depMap.get(fileName)) {
changedFiles.push({ fileName: id, event: change.event });
}
}
}
changedFiles.push({ fileName, event: change.event });
}
},
async writeBundle() {
const { compileApp } = (0, uni_cli_shared_1.resolveUTSCompiler)();
if (!(0, uni_cli_shared_1.isNormalCompileTarget)()) {
if (process.env.UNI_COMPILE_TARGET === 'ext-api') {
if (uniXKotlinCompiler) {
await uniXKotlinCompiler.addRootFile(path_1.default.join(tscOutputDir, 'main.uts.ts'));
await uniXKotlinCompiler.close();
const res = await compileApp(path_1.default.join(uvueOutputDir, 'main.uts'), {
pageCount: 0,
split: false,
disableSplitManifest: process.env.NODE_ENV !== 'development',
inputDir: uvueOutputDir,
outputDir: outputDir,
outFilename: `${process.env.UNI_COMPILE_EXT_API_OUT_FILE_NAME || 'components'}.kt`,
package: (0, uni_cli_shared_1.parseKotlinPackageWithPluginId)(process.env.UNI_COMPILE_EXT_API_PLUGIN_ID, true),
sourceMap: false,
uni_modules: [process.env.UNI_COMPILE_EXT_API_PLUGIN_ID],
extApiComponents: [],
uvueClassNamePrefix: utils_1.UVUE_CLASS_NAME_PREFIX,
transform: {
uvueClassNamePrefix: 'Uni',
uvueClassNameOnlyBasename: true,
},
});
if (res?.error) {
throw res.error;
}
}
}
return;
}
if (uniXKotlinCompiler) {
if (changedFiles.length) {
const files = changedFiles.splice(0);
await uniXKotlinCompiler.invalidate(files);
}
else if (isFirst) {
await uniXKotlinCompiler.addRootFile(path_1.default.join(tscOutputDir, 'main.uts.ts'));
}
}
let pageCount = 0;
if (isFirst) {
isFirst = false;
// 自动化测试时,不显示页面数量进度条
// if (!process.env.UNI_AUTOMATOR_WS_ENDPOINT) {
pageCount = parseInt(process.env.UNI_APP_X_PAGE_COUNT) || 0;
// }
}
// x 上暂时编译所有uni ext api,不管代码里是否调用了
await (0, uni_cli_shared_1.buildUniExtApis)();
const uniCloudObjectInfo = (0, utils_1.getUniCloudObjectInfo)(uniCloudSpaceList);
if (uniCloudObjectInfo.length > 0) {
process.env.UNI_APP_X_UNICLOUD_OBJECT = 'true';
}
else {
process.env.UNI_APP_X_UNICLOUD_OBJECT = 'false';
}
const res = await compileApp(path_1.default.join(uvueOutputDir, 'main.uts'), {
pageCount,
uniCloudObjectInfo,
split: split !== false,
disableSplitManifest: process.env.NODE_ENV !== 'development',
inputDir: uvueOutputDir,
outputDir: outputDir,
package: 'uni.' + (manifestJson.appid || utils_1.DEFAULT_APPID).replace(/_/g, ''),
sourceMap: (0, uni_cli_shared_1.enableSourceMap)(),
uni_modules: [...(0, uni_cli_shared_1.getCurrentCompiledUTSPlugins)()],
extApis: (0, uni_cli_shared_1.parseUniExtApiNamespacesOnce)(process.env.UNI_UTS_PLATFORM, process.env.UNI_UTS_TARGET_LANGUAGE),
extApiComponents: [...(0, utils_2.getExtApiComponents)()],
uvueClassNamePrefix: utils_1.UVUE_CLASS_NAME_PREFIX,
autoImports: await (0, uni_cli_shared_1.initUTSKotlinAutoImportsOnce)(),
extApiProviders: parseUniExtApiProviders(),
uniModulesArtifacts: (0, uni_cli_shared_1.parseUniModulesArtifacts)(),
env: parseProcessEnv(resolvedConfig),
});
if (uniXKotlinCompiler && process.env.NODE_ENV !== 'development') {
await uniXKotlinCompiler.close();
}
if (res) {
if (process.env.NODE_ENV === 'development') {
const files = [];
if (process.env.UNI_APP_UTS_CHANGED_FILES) {
try {
files.push(...JSON.parse(process.env.UNI_APP_UTS_CHANGED_FILES));
}
catch (e) { }
}
if (res.changed) {
// 触发了kotlinc编译,且没有编译成功
if (!res.changed.length && res.kotlinc) {
throw new Error('编译失败');
}
files.push(...res.changed);
}
process.env.UNI_APP_UTS_CHANGED_FILES = JSON.stringify([
...new Set(files),
]);
}
else {
// 生产环境,记录使用到的modules
const modules = res.inject_modules;
const manifest = (0, manifestJson_1.getOutputManifestJson)();
if (manifest) {
// 执行了摇树逻辑,就需要设置 modules 节点
(0, utils_2.updateManifestModules)(manifest, modules);
fs_extra_1.default.outputFileSync(path_1.default.resolve(process.env.UNI_OUTPUT_DIR, 'manifest.json'), JSON.stringify(manifest, null, 2));
}
}
}
},
};
}
exports.uniAppPlugin = uniAppPlugin;
function normalizeFilename(filename, isMain = false) {
if (isMain) {
return 'main.uts';
}
return (0, utils_1.parseUTSRelativeFilename)(filename, process.env.UNI_INPUT_DIR);
}
function commentUnoCssImport(code) {
// 使用正则表达式匹配 'import 'virtual:uno.css'' 语句
const regex = /^import\s+['"]virtual:uno\.css['"];?/gm;
return code.replace(regex, '// $&');
}
function normalizeCode(code, isMain = false) {
code = commentUnoCssImport(code);
if (!(0, uni_cli_shared_1.isNormalCompileTarget)()) {
return code;
}
if (!isMain) {
return code;
}
const automatorCode = process.env.UNI_AUTOMATOR_WS_ENDPOINT &&
process.env.UNI_AUTOMATOR_APP_WEBVIEW !== 'true'
? 'initAutomator();'
: '';
return `${code}
export function main(app: IApp) {
definePageRoutes();
defineAppConfig();
${automatorCode}
(createApp()['app'] as VueApp).mount(app, ${utils_1.UVUE_CLASS_NAME_PREFIX}UniApp());
}
`;
}
function parseUniExtApiProviders() {
const providers = [];
const customProviders = (0, uni_cli_shared_1.getUniExtApiProviderRegisters)();
customProviders.forEach((provider) => {
providers.push([provider.service, provider.name, provider.class]);
});
return providers;
}
function parseProcessEnv(resolvedConfig) {
const env = {};
const defines = {};
const userDefines = resolvedConfig.define;
Object.keys(userDefines).forEach((key) => {
if (key.startsWith('process.env.')) {
defines[key.replace('process.env.', '')] = userDefines[key];
}
});
(0, shared_1.extend)(defines, resolvedConfig.env);
Object.keys(defines).forEach((key) => {
let value = defines[key];
if ((0, shared_1.isString)(value)) {
try {
value = JSON.parse(value);
}
catch (e) { }
}
if (!(0, shared_1.isString)(value)) {
value = JSON.stringify(value);
}
env[key] = value;
});
return env;
}
+7
View File
@@ -0,0 +1,7 @@
import type { Plugin } from 'vite';
import { type FilterPattern } from '@rollup/pluginutils';
export interface UniPrePluginOptions {
include?: FilterPattern;
exclude?: FilterPattern;
}
export declare function uniPrePlugin(options?: UniPrePluginOptions): Plugin;
+53
View File
@@ -0,0 +1,53 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniPrePlugin = void 0;
const path_1 = __importDefault(require("path"));
const debug_1 = __importDefault(require("debug"));
const pluginutils_1 = require("@rollup/pluginutils");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const debugPreJs = (0, debug_1.default)('uni:pre-js');
const debugPreHtml = (0, debug_1.default)('uni:pre-html');
// const debugPreJsTry = debug('uni:pre-js-try')
const PRE_HTML_EXTNAME = ['.vue', '.uvue'];
const PRE_JS_EXTNAME = ['.json', '.css', '.uts', '.ts'].concat(PRE_HTML_EXTNAME);
function uniPrePlugin(options = {}) {
const filter = (0, pluginutils_1.createFilter)(options.include, options.exclude);
const preJsFile = uni_cli_shared_1.preUVueJs;
const preHtmlFile = uni_cli_shared_1.preUVueHtml;
return {
name: 'uni:pre-android',
enforce: 'pre',
transform(code, id) {
if (!filter(id)) {
return;
}
const { filename } = (0, uni_cli_shared_1.parseVueRequest)(id);
const extname = path_1.default.extname(filename);
const isHtml = PRE_HTML_EXTNAME.includes(extname);
const isJs = PRE_JS_EXTNAME.includes(extname);
const isPre = isHtml || isJs;
if (isPre) {
// debugPreJsTry(id)
}
const hasEndif = isPre && code.includes('#endif');
if (!hasEndif) {
return;
}
if (isHtml) {
code = preHtmlFile(code);
debugPreHtml(id);
}
if (isJs) {
code = preJsFile(code);
debugPreJs(id);
}
return {
code,
};
},
};
}
exports.uniPrePlugin = uniPrePlugin;
@@ -0,0 +1,2 @@
import type { Plugin } from 'vite';
export declare function uniCloudPlugin(): Plugin;
+45
View File
@@ -0,0 +1,45 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniCloudPlugin = void 0;
const path_1 = __importDefault(require("path"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
const uniCloudSpaceList = (0, utils_1.getUniCloudSpaceList)();
function uniCloudPlugin() {
if (!(process.env.UNI_COMPILE_TARGET === 'ext-api' &&
process.env.UNI_APP_NEXT_WORKSPACE)) {
(0, uni_cli_shared_1.addUTSEasyComAutoImports)((0, uni_cli_shared_1.normalizePath)(path_1.default.resolve((0, uni_cli_shared_1.resolveComponentsLibPath)(), 'unicloud-db', 'index.uts')), ['mixinDatacom', 'uniCloudMixinDatacom']);
}
return {
name: 'uni:app-unicloud',
apply: 'build',
generateBundle(_, bundle) {
if (uniCloudSpaceList.length === 0) {
return;
}
if (bundle[(0, utils_1.ENTRY_FILENAME)()]) {
const asset = bundle[(0, utils_1.ENTRY_FILENAME)()];
asset.source =
asset.source +
`
export class UniCloudConfig extends io.dcloud.unicloud.InternalUniCloudConfig {
override isDev : boolean = ${process.env.NODE_ENV === 'development' ? 'true' : 'false'}
override spaceList : string = ${JSON.stringify(JSON.stringify(uniCloudSpaceList.map((item) => {
const itemCopy = { ...item };
delete itemCopy.workspaceFolder;
return itemCopy;
})))}
override debuggerInfo ?: string = ${JSON.stringify(process.env.UNICLOUD_DEBUG || null)}
override secureNetworkEnable : boolean = false
override secureNetworkConfig ?: string = ""
constructor() { super() }
}
`;
}
},
};
}
exports.uniCloudPlugin = uniCloudPlugin;
+41
View File
@@ -0,0 +1,41 @@
import { type ImportSpecifier } from 'es-module-lexer';
import { type Import } from 'unimport';
import type { /*SourceMapInput, */ PluginContext } from 'rollup';
import type { Position } from '@vue/compiler-core';
export declare const UVUE_CLASS_NAME_PREFIX = "Gen";
export declare const DEFAULT_APPID = "__UNI__uniappx";
export declare const ENTRY_FILENAME: () => "main.uts.ts" | "main.uts";
export declare function wrapResolve(resolve: PluginContext['resolve']): PluginContext['resolve'];
export declare function createTryResolve(importer: string, resolve: PluginContext['resolve'], offsetStart?: Position, origCode?: string): (source: string, code: string, { ss, se }: ImportSpecifier) => Promise<boolean | void>;
export declare function parseImports(code: string, tryResolve?: ReturnType<typeof createTryResolve>): Promise<string>;
export declare function createResolveError(code: string, msg: string, start: Position, end: Position): import("rollup").RollupError;
export declare function kotlinOutDir(): string;
export declare function isVue(filename: string): boolean;
export declare function stringifyMap(obj: unknown, ts?: boolean): string;
export declare function parseUTSRelativeFilename(filename: string, root?: string): string;
export declare function parseUTSImportFilename(filename: string): string;
type UniCloudSpace = {
provider: string;
spaceName: string;
spaceId: string;
clientSecret?: string;
endpoint?: string;
workspaceFolder?: string;
};
export declare function getUniCloudSpaceList(): Array<UniCloudSpace>;
type UniCloudObjectInfo = {
name: string;
methodList: string[];
};
export declare function getUniCloudObjectInfo(uniCloudSpaceList: Array<UniCloudSpace>): Array<UniCloudObjectInfo>;
export declare function transformAutoImport(code: string, id: string, ignore?: string[]): Promise<{
code: string;
}>;
export declare function genAutoImportsCode(imports: Import[]): string;
export declare function transformUniCloudMixinDataCom(code: string): string;
export declare function detectAutoImports(code: string, id: string, ignore?: string[]): Promise<{
matchedImports: Import[];
}> | {
matchedImports: never[];
};
export {};
+368
View File
@@ -0,0 +1,368 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectAutoImports = exports.transformUniCloudMixinDataCom = exports.genAutoImportsCode = exports.transformAutoImport = exports.getUniCloudObjectInfo = exports.getUniCloudSpaceList = exports.parseUTSImportFilename = exports.parseUTSRelativeFilename = exports.stringifyMap = exports.isVue = exports.kotlinOutDir = exports.createResolveError = exports.parseImports = exports.createTryResolve = exports.wrapResolve = exports.ENTRY_FILENAME = exports.DEFAULT_APPID = exports.UVUE_CLASS_NAME_PREFIX = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const es_module_lexer_1 = require("es-module-lexer");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const shared_1 = require("@vue/shared");
const unimport_1 = require("unimport");
const errors_1 = require("./uvue/compiler/errors");
exports.UVUE_CLASS_NAME_PREFIX = 'Gen';
exports.DEFAULT_APPID = '__UNI__uniappx';
const ENTRY_FILENAME = () => process.env.UNI_APP_X_TSC === 'true' ? 'main.uts.ts' : 'main.uts';
exports.ENTRY_FILENAME = ENTRY_FILENAME;
function wrapResolve(resolve) {
return async (source, importer, options) => {
try {
return await resolve(source, importer, options);
}
catch (e) {
// import "@/pages/logo.png" 可能会报 Cannot find module 错误
}
return null;
};
}
exports.wrapResolve = wrapResolve;
function createTryResolve(importer, resolve, offsetStart, origCode = '') {
return async (source, code, { ss, se }) => {
const resolved = await wrapResolve(resolve)(source, importer);
if (!resolved) {
const { start, end } = (0, uni_cli_shared_1.offsetToStartAndEnd)(code, ss, se);
if (offsetStart) {
if (start.line === 1) {
start.column = start.column + offsetStart.column;
if (end.line === 1) {
end.column = end.column + offsetStart.column;
}
}
const offsetLine = offsetStart.line - 1;
start.line = start.line + offsetLine;
end.line = end.line + offsetLine;
}
throw createResolveError(origCode || code, (0, uni_cli_shared_1.createResolveErrorMsg)(source, importer), start, end);
}
};
}
exports.createTryResolve = createTryResolve;
async function parseImports(code, tryResolve) {
await es_module_lexer_1.init;
let res = [[], [], false, false];
try {
res = (0, es_module_lexer_1.parse)(code);
}
catch (err) {
const message = err.message;
if (message) {
const matches = message.match(/@:(\d+):(\d+)/);
if (matches) {
throw (0, uni_cli_shared_1.createRollupError)('', '', (0, errors_1.createCompilerError)(0, {
start: {
offset: 0,
line: parseInt(matches[1]),
column: parseInt(matches[2]),
},
}, { 0: `Parse error` }, ''), code);
}
}
throw err;
}
const imports = res[0];
const importsCode = [];
for (const specifier of imports) {
const source = code.slice(specifier.s, specifier.e);
if (tryResolve) {
const res = await tryResolve(source, code, specifier);
if (res === false) {
// 忽略该import
continue;
}
}
importsCode.push(`import "${source}"`);
}
return importsCode.concat(parseUniExtApiImports(code)).join('\n');
}
exports.parseImports = parseImports;
function createResolveError(code, msg, start, end) {
return (0, uni_cli_shared_1.createRollupError)('', '', (0, errors_1.createCompilerError)(0, {
start,
end,
}, { 0: msg }, ''), code);
}
exports.createResolveError = createResolveError;
// @ts-expect-error 暂时不用
function genImportsCode(code, imports) {
const chars = code.split('');
const keepChars = [];
imports.forEach(({ ss, se }) => {
for (let i = ss; i <= se; i++) {
keepChars.push(i);
}
});
for (let i = 0; i < chars.length; i++) {
if (!keepChars.includes(i)) {
const char = chars[i];
if (char !== '\r' && char !== '\n') {
chars[i] = ' ';
}
}
}
return chars.join('');
}
function parseUniExtApiImports(code) {
if (!process.env.UNI_UTS_PLATFORM) {
return [];
}
const extApis = (0, uni_cli_shared_1.parseUniExtApiNamespacesJsOnce)(process.env.UNI_UTS_PLATFORM, process.env.UNI_UTS_TARGET_LANGUAGE);
const pattern = /uni\.(\w+)/g;
const apis = new Set();
let match;
while ((match = pattern.exec(code)) !== null) {
apis.add(match[1]);
}
const imports = [];
apis.forEach((api) => {
const extApi = extApis[api];
if (extApi) {
imports.push(`import "${extApi[0]}"`);
}
});
return imports;
}
function kotlinOutDir() {
return path_1.default.join(process.env.UNI_OUTPUT_DIR, '../.kotlin');
}
exports.kotlinOutDir = kotlinOutDir;
function isVue(filename) {
return filename.endsWith('.vue') || filename.endsWith('.uvue');
}
exports.isVue = isVue;
function stringifyMap(obj, ts = false) {
return serialize(obj, ts);
}
exports.stringifyMap = stringifyMap;
function serialize(obj, ts = false) {
if ((0, shared_1.isString)(obj)) {
return `"${obj}"`;
}
else if ((0, shared_1.isPlainObject)(obj)) {
const entries = Object.entries(obj).map(([key, value]) => `[${serialize(key, ts)},${serialize(value, ts)}]`);
if (entries.length) {
return `utsMapOf([${entries.join(',')}])`;
}
if (ts) {
return `utsMapOf<string, any | null>()`;
}
return `utsMapOf()`;
}
else if ((0, shared_1.isArray)(obj)) {
return `[${obj.map((item) => serialize(item, ts)).join(',')}]`;
}
else {
return String(obj);
}
}
function parseUTSRelativeFilename(filename, root) {
if (!path_1.default.isAbsolute(filename)) {
return filename;
}
return (0, uni_cli_shared_1.normalizeNodeModules)(path_1.default.relative(root ?? process.env.UNI_INPUT_DIR, filename));
}
exports.parseUTSRelativeFilename = parseUTSRelativeFilename;
function parseUTSImportFilename(filename) {
if (!path_1.default.isAbsolute(filename)) {
return filename;
}
return ('@/' +
(0, uni_cli_shared_1.normalizeNodeModules)(path_1.default.relative(process.env.UNI_INPUT_DIR, filename)));
}
exports.parseUTSImportFilename = parseUTSImportFilename;
let uniCloudSpaceList;
function getUniCloudSpaceList() {
if (uniCloudSpaceList) {
return uniCloudSpaceList;
}
if (!process.env.UNI_CLOUD_SPACES) {
uniCloudSpaceList = [];
return uniCloudSpaceList;
}
try {
const spaces = JSON.parse(process.env.UNI_CLOUD_SPACES);
if (!Array.isArray(spaces)) {
uniCloudSpaceList = [];
return uniCloudSpaceList;
}
uniCloudSpaceList = spaces.map((space) => {
if (space.provider === 'tcb') {
space.provider = 'tencent';
}
if (!space.provider && space.clientSecret) {
space.provider = 'aliyun';
}
switch (space.provider) {
case 'aliyun':
case 'dcloud':
return {
provider: space.provider || 'aliyun',
spaceName: space.name,
spaceId: space.id,
clientSecret: space.clientSecret,
endpoint: space.apiEndpoint,
workspaceFolder: space.workspaceFolder,
};
case 'alipay': {
return {
provider: space.provider,
spaceName: space.name,
spaceId: space.id,
spaceAppId: space.spaceAppId,
accessKey: space.accessKey,
secretKey: space.secretKey,
workspaceFolder: space.workspaceFolder,
};
}
case 'tencent':
default: {
return {
provider: space.provider,
spaceName: space.name,
spaceId: space.id,
workspaceFolder: space.workspaceFolder,
};
}
}
});
}
catch (e) {
console.error(e);
}
uniCloudSpaceList = uniCloudSpaceList || [];
if (uniCloudSpaceList.length > 1) {
console.warn('Multi uniCloud space is not supported yet.');
}
return uniCloudSpaceList;
}
exports.getUniCloudSpaceList = getUniCloudSpaceList;
function getUniCloudObjectInfo(uniCloudSpaceList) {
let uniCloudWorkspaceFolder = process.env.UNI_INPUT_DIR.endsWith('src')
? path_1.default.resolve(process.env.UNI_INPUT_DIR, '..')
: process.env.UNI_INPUT_DIR;
let serviceProvider = 'aliyun';
if (uniCloudSpaceList && uniCloudSpaceList.length > 0) {
const space = uniCloudSpaceList[0];
if (space.workspaceFolder) {
uniCloudWorkspaceFolder = space.workspaceFolder;
}
serviceProvider = space.provider === 'tencent' ? 'tcb' : space.provider;
}
else {
serviceProvider =
['aliyun', 'tcb', 'alipay', 'dcloud'].find((item) => fs_1.default.existsSync(path_1.default.resolve(uniCloudWorkspaceFolder, 'uniCloud-' + item))) || 'aliyun';
}
try {
const { getWorkspaceObjectInfo } = require('../../../lib/unicloud-utils');
return getWorkspaceObjectInfo(uniCloudWorkspaceFolder, serviceProvider);
}
catch (e) {
console.error(e.message);
process.exit(1);
}
}
exports.getUniCloudObjectInfo = getUniCloudObjectInfo;
async function transformAutoImport(code, id, ignore = []) {
const { matchedImports } = await detectAutoImports(code, id, ignore);
if (matchedImports.length) {
return {
code: code + '\n' + genAutoImportsCode(matchedImports),
};
}
return { code };
}
exports.transformAutoImport = transformAutoImport;
function genAutoImportsCode(imports) {
const codes = [];
imports.forEach(({ name, as, from }) => {
if (as && name !== as) {
codes.push(`import { ${name} as ${as} } from "${parseUTSImportFilename(from)}"`);
}
else {
codes.push(`import { ${name} } from "${parseUTSImportFilename(from)}"`);
}
});
return codes.join('\n');
}
exports.genAutoImportsCode = genAutoImportsCode;
let detectImports;
function transformUniCloudMixinDataCom(code) {
// 将 uniCloud.mixinDatacom 替换为 uniCloudMixinDatacom
// 然后 autoImport 会自动导入 uniCloudMixinDatacom
if (code.includes('uniCloud.mixinDatacom')) {
return code.replace(/uniCloud\.mixinDatacom/g, 'uniCloudMixinDatacom');
}
return code;
}
exports.transformUniCloudMixinDataCom = transformUniCloudMixinDataCom;
function detectAutoImports(code, id, ignore = []) {
// 目前硬编码
if (id.includes('index.module.uts')) {
return { matchedImports: [] };
}
if (!detectImports) {
detectImports = initAutoImport().detectImports;
}
else {
const autoImports = (0, uni_cli_shared_1.getUTSEasyComAutoImports)();
const sources = Object.keys(autoImports);
if (detectImports.key !== sources.sort().join(',')) {
detectImports = initAutoImport().detectImports;
}
}
return detectImports(code, id, ignore);
}
exports.detectAutoImports = detectAutoImports;
function initAutoImport() {
const autoImports = (0, uni_cli_shared_1.getUTSEasyComAutoImports)();
const sources = Object.keys(autoImports);
if (!sources.length) {
const detectImports = async (_code, _id, _ignore = []) => {
return { matchedImports: [] };
};
detectImports.key = 'default';
return {
detectImports,
};
}
const imports = [];
sources.forEach((source) => {
autoImports[source].forEach(([name, as]) => {
imports.push({
name,
as,
from: source,
});
});
});
const { detectImports: uniDetectImports } = (0, unimport_1.createUnimport)({
imports,
});
const detectImports = async function (code, id, ignore = []) {
// const start = Date.now()
const result = await uniDetectImports(code);
// console.log('detectImports[' + id + ']耗时:' + (Date.now() - start))
return {
matchedImports: result.matchedImports.filter((item) => {
if (item.as && item.name !== item.as) {
return !ignore.includes(item.as);
}
return !ignore.includes(item.name);
}),
};
};
detectImports.key = sources.sort().join(',');
return {
detectImports,
};
}
@@ -0,0 +1,5 @@
import type { SFCDescriptor } from '@vue/compiler-sfc';
export declare function genScript({ script }: SFCDescriptor, { genDefaultAs }: {
genDefaultAs?: string;
}): string;
export declare function genDefaultScriptCode(genDefaultAs?: string): string;
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genDefaultScriptCode = exports.genScript = void 0;
function genScript({ script }, { genDefaultAs }) {
if (!script) {
return genDefaultScriptCode(genDefaultAs);
}
return ('\n'.repeat(script.loc.start.line - 1) +
`${script.content}
`);
}
exports.genScript = genScript;
function genDefaultScriptCode(genDefaultAs) {
if (genDefaultAs) {
return `const ${genDefaultAs} = defineComponent({})
export default ${genDefaultAs}`;
}
return `
export default {}
`;
}
exports.genDefaultScriptCode = genDefaultScriptCode;
@@ -0,0 +1,11 @@
import type { SFCDescriptor } from '@vue/compiler-sfc';
import type { PluginContext, TransformPluginContext } from 'rollup';
import { type ResolvedOptions } from '../descriptorCache';
export declare function genStyle(_: SFCDescriptor, { className }: {
className: string;
}): string;
export declare function genJsStylesCode(descriptor: SFCDescriptor, pluginContext: PluginContext): Promise<string>;
export declare function transformStyle(code: string, descriptor: SFCDescriptor, index: number, options: ResolvedOptions, pluginContext: TransformPluginContext, filename: string): Promise<{
code: string;
map: null;
} | null>;
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformStyle = exports.genJsStylesCode = exports.genStyle = void 0;
const descriptorCache_1 = require("../descriptorCache");
function genStyle(_, { className }) {
return `/*${className}Styles*/`;
}
exports.genStyle = genStyle;
async function genJsStylesCode(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) {
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');
const srcQuery = style.src ? '&src=true' : '';
const query = `?vue&type=style&index=${i}${srcQuery}`;
const styleRequest = src + query + attrsQuery;
stylesCode += `\nimport ${JSON.stringify(styleRequest)}`;
}
}
return stylesCode;
}
exports.genJsStylesCode = genJsStylesCode;
/**
* 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'];
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;
}
async function transformStyle(code, descriptor, index, options, pluginContext, filename) {
const block = descriptor.styles[index];
// vite already handles pre-processors and CSS module so this is only
// applying SFC-specific transforms like scoped mode and CSS vars rewrite (v-bind(var))
const result = await options.compiler.compileStyleAsync({
filename: descriptor.filename,
id: `data-v-${descriptor.id}`,
isProd: true,
source: code,
});
if (result.errors.length) {
result.errors.forEach((error) => {
if (error.line && error.column) {
error.loc = {
file: descriptor.filename,
line: error.line + block.loc.start.line,
column: error.column,
};
}
pluginContext.error(error);
});
return null;
}
return {
code: result.code,
map: null,
};
}
exports.transformStyle = transformStyle;
@@ -0,0 +1,8 @@
import type { SFCDescriptor } from '@vue/compiler-sfc';
import type { CodegenResult, TemplateCompilerOptions } from '../compiler/options';
import type { TransformPluginContext } from 'rollup';
export declare function genTemplate({ template }: SFCDescriptor, options: TemplateCompilerOptions & {
genDefaultAs?: string;
}): CodegenResult;
export declare const genTemplateCode: typeof genTemplate;
export declare function tryResolveTemplateSrc(descriptor: SFCDescriptor, pluginContext?: TransformPluginContext): Promise<void>;
@@ -0,0 +1,74 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.tryResolveTemplateSrc = exports.genTemplateCode = exports.genTemplate = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_1 = require("../compiler");
const utils_1 = require("../compiler/utils");
const descriptorCache_1 = require("../descriptorCache");
function genTemplate({ template }, options) {
if (!template || !template.content) {
return {
code: options.mode === 'module'
? (0, utils_1.genRenderFunctionDecl)(options) + ` { return null }`
: `null`,
easyComponentAutoImports: {},
preamble: '',
elements: [],
imports: [],
};
}
const { preprocessLang, preprocessOptions } = options;
const preprocessor = preprocessLang
? require('@vue/consolidate')[preprocessLang]
: false;
return (0, compiler_1.compile)(preprocessor
? preprocess({ source: template.content, filename: '', preprocessOptions }, preprocessor)
: template.content, options);
}
exports.genTemplate = genTemplate;
exports.genTemplateCode = genTemplate;
function preprocess({ source, filename, preprocessOptions, }, preprocessor) {
// Consolidate exposes a callback based API, but the callback is in fact
// called synchronously for most templating engines. In our case, we have to
// expose a synchronous API so that it is usable in Jest transforms (which
// have to be sync because they are applied via Node.js require hooks)
let res = '';
let err = null;
preprocessor.render(source, { filename, ...preprocessOptions }, (_err, _res) => {
if (_err)
err = _err;
res = _res;
});
if (err)
throw err;
return res;
}
async function tryResolveTemplateSrc(descriptor, pluginContext) {
if (!pluginContext) {
return;
}
if (!descriptor.template) {
return;
}
if (descriptor.template.src) {
const resolved = await pluginContext.resolve(descriptor.template.src, descriptor.filename);
if (resolved) {
const filename = resolved.id;
// 如果引入的vue文件,读取对应的template
if ((0, uni_cli_shared_1.isVueSfcFile)(filename)) {
const srcDescriptor = (0, descriptorCache_1.getDescriptor)(filename, (0, descriptorCache_1.getResolvedOptions)());
if (srcDescriptor && srcDescriptor.template?.content) {
descriptor.template.content = srcDescriptor.template.content;
}
}
else {
descriptor.template.content = (0, uni_cli_shared_1.preUVueHtml)(fs_extra_1.default.readFileSync(filename, 'utf-8'));
}
}
}
}
exports.tryResolveTemplateSrc = tryResolveTemplateSrc;
@@ -0,0 +1,25 @@
import { SourceMapGenerator } from 'source-map-js';
import { type JSChildNode, type RootNode, type SSRCodegenNode, type TemplateChildNode } from '@vue/compiler-core';
import { type ParserPlugin } from '@babel/parser';
import type { CodegenOptions, CodegenResult } from './options';
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode;
export interface CodegenContext extends Required<Omit<CodegenOptions, 'sourceMapGeneratedLine' | 'className' | 'originalLineOffset' | 'generatedLineOffset' | 'inMap'>> {
source: string;
code: string;
easyComponentAutoImports: Record<string, [string, string]>;
line: number;
column: number;
offset: number;
indentLevel: number;
map?: SourceMapGenerator;
expressionPlugins: ParserPlugin[];
helper(key: symbol): string;
push(code: string, node?: CodegenNode): void;
indent(): void;
deindent(withoutNewLine?: boolean): void;
newline(): void;
}
export declare function generate(ast: RootNode, options?: CodegenOptions & {
genDefaultAs?: string;
}): CodegenResult;
export {};
@@ -0,0 +1,654 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generate = void 0;
const source_map_js_1 = require("source-map-js");
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const parser_1 = require("@babel/parser");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("./utils");
const runtimeHelpers_1 = require("./runtimeHelpers");
const transformExpression_1 = require("./transforms/transformExpression");
const types_1 = require("@babel/types");
const transformSlotPropsDestructuring_1 = require("./transforms/transformSlotPropsDestructuring");
function createCodegenContext(ast, { rootDir = '', targetLanguage = 'kotlin', mode = 'default', prefixIdentifiers = mode === 'module', bindingMetadata = {}, inline = false, sourceMap = false, filename = '', matchEasyCom = shared_1.NOOP, parseUTSComponent = shared_1.NOOP, originalLineOffset = 0, generatedLineOffset = 0, }) {
const context = {
rootDir,
targetLanguage,
mode,
prefixIdentifiers,
bindingMetadata,
inline,
sourceMap,
filename,
source: ast.loc.source,
code: ``,
easyComponentAutoImports: {},
column: 1,
line: 1,
offset: 0,
indentLevel: 0,
map: undefined,
expressionPlugins: ['typescript'],
matchEasyCom,
parseUTSComponent,
helper(key) {
return `${compiler_core_1.helperNameMap[key]}`;
},
push(code, node) {
context.code += code;
if (context.map) {
if (node) {
let name;
if (node.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
const content = node.content.replace(/^_ctx\./, '');
if (content !== node.content && (0, compiler_core_1.isSimpleIdentifier)(content)) {
name = content;
}
}
addMapping(node.loc.start, name);
}
(0, compiler_core_1.advancePositionWithMutation)(context, code);
if (node && node.loc !== compiler_core_1.locStub) {
addMapping(node.loc.end);
}
}
},
indent() {
newline(++context.indentLevel);
},
deindent(withoutNewLine = false) {
if (withoutNewLine) {
--context.indentLevel;
}
else {
newline(--context.indentLevel);
}
},
newline() {
newline(context.indentLevel);
},
};
function newline(n) {
context.push('\n' + ` `.repeat(n));
}
function addMapping(loc, name) {
context.map.addMapping({
name,
source: context.filename,
original: {
line: loc.line + originalLineOffset,
column: loc.column - 1, // source-map column is 0 based
},
generated: {
line: context.line + generatedLineOffset,
column: context.column - 1,
},
});
}
if (sourceMap) {
// lazy require source-map implementation, only in non-browser builds
context.map = new source_map_js_1.SourceMapGenerator();
context.map.setSourceContent(filename, context.source);
}
return context;
}
function generate(ast, options = {}) {
const context = createCodegenContext(ast, options);
const { mode, deindent, indent, push, newline } = context;
const isSetupInlined = !!options.inline;
// preambles
// in setup() inline mode, the preamble is generated in a sub context
// and returned separately.
// const preambleContext = isSetupInlined
// ? createCodegenContext(ast, options)
// : context
const preambleContext = createCodegenContext(ast, options);
if (mode === 'module') {
genEasyComImports(ast.components, preambleContext);
if (ast.imports.length) {
genImports(ast.imports, preambleContext);
}
push((0, utils_1.genRenderFunctionDecl)(options) + ` {`);
newline();
if (!isSetupInlined) {
push(`const _ctx = this`);
newline();
push(`const _cache = this.$.renderCache`);
}
// generate asset resolution statements
if (ast.components.length) {
newline();
genAssets(ast.components, 'component', context);
if (ast.directives.length || ast.temps > 0) {
newline();
}
}
if (ast.directives.length) {
genAssets(ast.directives, 'directive', context);
if (ast.temps > 0) {
newline();
}
}
if (ast.components.length || ast.directives.length || ast.temps) {
newline();
}
indent();
push(`return `);
}
if (ast.codegenNode) {
genNode(ast.codegenNode, context);
}
else {
push(`null`);
}
if (mode === 'module') {
deindent();
push(`}`);
}
return {
ast,
code: context.code,
preamble: preambleContext.code,
easyComponentAutoImports: context.easyComponentAutoImports,
// SourceMapGenerator does have toJSON() method but it's not in the types
map: context.map ? context.map.toJSON() : undefined,
// @ts-expect-error
elements: ast.elements,
};
}
exports.generate = generate;
function genImports(importsOptions, context) {
if (!importsOptions.length) {
return;
}
importsOptions.forEach((imports) => {
if ((0, shared_1.isString)(imports.exp)) {
if (imports.exp) {
context.push(`import ${imports.exp} from '${imports.path}'`);
}
else {
context.push(`import '${imports.path}'`);
}
}
else if ((0, uni_cli_shared_1.isSimpleExpressionNode)(imports.exp)) {
// 解决静态资源导入 sourcemap 映射问题
context.push(`import ${imports.exp.content} from '${imports.path}'`, imports.exp);
}
else {
context.push(`import `);
genNode(imports.exp, context);
context.push(` from '${imports.path}'`);
}
context.newline();
});
}
function genEasyComImports(components, { push, newline, matchEasyCom, rootDir }) {
for (let i = 0; i < components.length; i++) {
let id = components[i];
const maybeSelfReference = id.endsWith('__self');
if (maybeSelfReference) {
id = id.slice(0, -6);
}
const source = matchEasyCom(id, true);
if (source) {
if (source.includes('?uts-proxy')) {
push(`import { ${genEncryptUniModuleEasyComClass(id, parseUniModuleId(source))} } from '${source}';`);
}
else {
const componentId = (0, compiler_core_1.toValidAssetId)(id, 'easycom');
push(`import ${componentId} from '${source}'`);
}
newline();
}
}
}
function genAssets(assets, type, { helper, push, newline, easyComponentAutoImports, matchEasyCom, rootDir, }) {
const resolver = helper(type === 'component' ? runtimeHelpers_1.RESOLVE_COMPONENT : runtimeHelpers_1.RESOLVE_DIRECTIVE);
for (let i = 0; i < assets.length; i++) {
let id = assets[i];
// potential component implicit self-reference inferred from SFC filename
const maybeSelfReference = id.endsWith('__self');
if (maybeSelfReference) {
id = id.slice(0, -6);
}
let assetCode = '';
if (type === 'component') {
const source = matchEasyCom(id, false);
if (source) {
const componentId = (0, compiler_core_1.toValidAssetId)(id, type);
// 加密 easyCom
if (source.includes('?uts-proxy')) {
const easyComponentId = genEncryptUniModuleEasyComClass(id, parseUniModuleId(source));
assetCode = `const ${componentId} = ${helper(runtimeHelpers_1.RESOLVE_EASY_COMPONENT)}(${JSON.stringify(id)},${easyComponentId})`;
}
else {
const easyComponentId = (0, compiler_core_1.toValidAssetId)(id, 'easycom');
assetCode = `const ${componentId} = ${helper(runtimeHelpers_1.RESOLVE_EASY_COMPONENT)}(${JSON.stringify(id)},${easyComponentId})`;
}
(0, utils_1.addEasyComponentAutoImports)(easyComponentAutoImports, rootDir, id, source);
}
}
if (!assetCode) {
assetCode = `const ${(0, compiler_core_1.toValidAssetId)(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})`;
}
push(assetCode);
if (i < assets.length - 1) {
newline();
}
}
}
function parseUniModuleId(source) {
const parts = source.split('/');
return parts[parts.length - 1].replace('?uts-proxy', '');
}
// GenUniModulesTestCom1ComponentsTestCom11TestCom11Class
function genEncryptUniModuleEasyComClass(componentName, uniModuleId) {
return (0, shared_1.capitalize)((0, shared_1.camelize)(`gen-uni-modules-${uniModuleId}-components-${componentName}-${componentName}-class`));
}
function isText(n) {
return ((0, shared_1.isString)(n) ||
n.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION ||
n.type === compiler_core_1.NodeTypes.TEXT ||
n.type === compiler_core_1.NodeTypes.INTERPOLATION ||
n.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION);
}
function genNodeListAsArray(nodes, context) {
const multilines = nodes.length > 3 || nodes.some((n) => (0, shared_1.isArray)(n) || !isText(n));
context.push(`[`);
multilines && context.indent();
genNodeList(nodes, context, multilines);
multilines && context.deindent();
context.push(`]`);
}
function genNodeList(nodes, context, multilines = false, comma = true) {
const { push, newline } = context;
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if ((0, shared_1.isString)(node)) {
push(node);
}
else if ((0, shared_1.isArray)(node)) {
genNodeListAsArray(node, context);
}
else {
genNode(node, context);
}
if (i < nodes.length - 1) {
if (multilines) {
comma && push(',');
newline();
}
else {
comma && push(', ');
}
}
}
}
function genNode(node, context) {
if ((0, shared_1.isString)(node)) {
context.push(node);
return;
}
if ((0, shared_1.isSymbol)(node)) {
context.push(context.helper(node));
return;
}
switch (node.type) {
case compiler_core_1.NodeTypes.ELEMENT:
case compiler_core_1.NodeTypes.IF:
case compiler_core_1.NodeTypes.FOR:
genNode(node.codegenNode, context);
break;
case compiler_core_1.NodeTypes.TEXT:
genText(node, context);
break;
case compiler_core_1.NodeTypes.SIMPLE_EXPRESSION:
genExpression(node, context);
break;
case compiler_core_1.NodeTypes.INTERPOLATION:
genInterpolation(node, context);
break;
case compiler_core_1.NodeTypes.TEXT_CALL:
genNode(node.codegenNode, context);
break;
case compiler_core_1.NodeTypes.COMPOUND_EXPRESSION:
genCompoundExpression(node, context);
break;
case compiler_core_1.NodeTypes.COMMENT:
genComment(node, context);
break;
case compiler_core_1.NodeTypes.VNODE_CALL:
genVNodeCall(node, context);
break;
case compiler_core_1.NodeTypes.JS_CALL_EXPRESSION:
genCallExpression(node, context);
break;
case compiler_core_1.NodeTypes.JS_OBJECT_EXPRESSION:
genObjectExpression(node, context);
break;
case compiler_core_1.NodeTypes.JS_ARRAY_EXPRESSION:
genArrayExpression(node, context);
break;
case compiler_core_1.NodeTypes.JS_FUNCTION_EXPRESSION:
genFunctionExpression(node, context);
break;
case compiler_core_1.NodeTypes.JS_CONDITIONAL_EXPRESSION:
genConditionalExpression(node, context);
break;
case compiler_core_1.NodeTypes.JS_CACHE_EXPRESSION:
genCacheExpression(node, context);
break;
case compiler_core_1.NodeTypes.JS_BLOCK_STATEMENT:
genNodeList(node.body, context, true, false);
break;
/* istanbul ignore next */
case compiler_core_1.NodeTypes.IF_BRANCH:
// noop
break;
default:
}
}
function genText(node, context) {
context.push(JSON.stringify(node.content), node);
}
function genExpression(node, context) {
const { content, isStatic } = node;
context.push(isStatic ? JSON.stringify(content) : content, node);
}
function genInterpolation(node, context) {
const { push, helper } = context;
push(`${helper(compiler_core_1.TO_DISPLAY_STRING)}(`);
genNode(node.content, context);
push(`)`);
}
function genCompoundExpression(node, context) {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if ((0, shared_1.isString)(child)) {
context.push(child);
}
else {
genNode(child, context);
}
}
}
function genExpressionAsPropertyKey(node, context) {
const { push } = context;
if (node.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
push(`[`);
genCompoundExpression(node, context);
push(`]`);
}
else if (node.isStatic) {
// only quote keys if necessary
const text = (0, compiler_core_1.isSimpleIdentifier)(node.content)
? node.content
: JSON.stringify(node.content);
push(text, node);
}
else {
push(`[${node.content}]`, node);
}
}
function genComment(node, context) {
const { push, helper } = context;
push(`${helper(compiler_core_1.CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);
}
function parseTag(tag, curNode, { parseUTSComponent, targetLanguage }) {
if ((0, shared_1.isString)(tag)) {
// 原生UTS组件
const utsComponentOptions = parseUTSComponent(tag.slice(1, -1), targetLanguage);
if (utsComponentOptions) {
return (0, compiler_core_1.createSimpleExpression)(utsComponentOptions.className + '.name', false, curNode.loc);
}
}
return tag;
}
function genVNodeCall(node, context) {
const { push, helper } = context;
const { tag, props, children, patchFlag, dynamicProps, directives,
// isBlock,
disableTracking, isComponent, } = node;
if (directives) {
push(helper(compiler_core_1.WITH_DIRECTIVES) + `(`);
}
const isBlock = false;
if (isBlock) {
push(`(${helper(compiler_core_1.OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);
}
const callHelper = isBlock
? (0, compiler_core_1.getVNodeBlockHelper)(false, isComponent)
: (0, compiler_core_1.getVNodeHelper)(false, isComponent);
push(helper(callHelper) + `(`, node);
genNodeList(genNullableArgs([
parseTag(tag, node, context),
props,
children,
patchFlag,
dynamicProps,
]), context);
push(`)`);
if (isBlock) {
push(`)`);
}
if (directives) {
push(`, `);
genNode(directives, context);
push(`)`);
}
}
function genNullableArgs(args) {
let i = args.length;
while (i--) {
if (args[i] != null)
break;
}
return args.slice(0, i + 1).map((arg) => arg || `null`);
}
// JavaScript
function genCallExpression(node, context) {
const { push, helper } = context;
const callee = (0, shared_1.isString)(node.callee) ? node.callee : helper(node.callee);
push(callee + `(`, node);
if (callee === helper(runtimeHelpers_1.RENDER_LIST)) {
genRenderList(node);
}
genNodeList(node.arguments, context);
push(`)`);
}
function genRenderList(node) {
node.arguments.forEach((argument) => {
if (argument.type === compiler_core_1.NodeTypes.JS_FUNCTION_EXPRESSION) {
argument.returnType = 'any';
}
});
}
function genObjectExpression(node, context) {
const { push, indent, deindent, newline } = context;
const { properties } = node;
if (!properties.length) {
push(`utsMapOf()`, node);
return;
}
push(`utsMapOf(`);
const multilines = properties.length > 1 ||
properties.some((p) => p.value.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION);
push(multilines ? `{` : `{ `);
multilines && indent();
for (let i = 0; i < properties.length; i++) {
const { key, value } = properties[i];
// key
genExpressionAsPropertyKey(key, context);
push(`: `);
// value
genNode(value, context);
if (i < properties.length - 1) {
// will only reach this if it's multilines
push(`,`);
newline();
}
}
multilines && deindent();
push(multilines ? `}` : ` }`);
push(`)`);
}
function genArrayExpression(node, context) {
genNodeListAsArray(node.elements, context);
}
function genFunctionExpression(node, context) {
const { push, indent, deindent } = context;
const { params, returns, body, newline, isSlot } = node;
if (isSlot) {
// wrap slot functions with owner context
push(`${compiler_core_1.helperNameMap[params ? runtimeHelpers_1.WITH_SCOPED_SLOT_CTX : runtimeHelpers_1.WITH_SLOT_CTX]}(`);
}
push(`(`, node);
if ((0, shared_1.isArray)(params)) {
genNodeList(params, context);
}
else if (params) {
if ((0, transformSlotPropsDestructuring_1.isDestructuringSlotProps)(isSlot, params) ||
params?.content === '{}') {
push(transformSlotPropsDestructuring_1.SLOT_PROPS_NAME);
}
else {
genNode(params, context);
}
}
if (node.returnType) {
push(`): ${node.returnType} => `);
}
else {
if (isSlot) {
if (params) {
// { data } :Qux
const paramsStr = (0, transformExpression_1.stringifyExpression)(params);
let code = ': Record<string, any | null>): any[] => ';
if (paramsStr.includes(':')) {
const ast = (0, parser_1.parseExpression)(`(${paramsStr})=>{}`, {
plugins: context.expressionPlugins,
});
// 判断是否已经指定了类型
if ((0, types_1.isArrowFunctionExpression)(ast) && ast.params[0].typeAnnotation) {
code = `): any[] => `;
}
}
push(code);
if ((0, transformSlotPropsDestructuring_1.isDestructuringSlotProps)(isSlot, params)) {
push('{');
(0, transformSlotPropsDestructuring_1.createDestructuringSlotProps)(params, context);
context.newline();
push('return ');
}
}
else {
push(`): any[] => `);
}
}
else {
push(`) => `);
}
}
if (newline || body) {
push(`{`);
indent();
}
if (returns) {
if (newline) {
push(`return `);
}
if ((0, shared_1.isArray)(returns)) {
genNodeListAsArray(returns, context);
}
else {
genNode(returns, context);
}
}
else if (body) {
genNode(body, context);
}
if (newline || body) {
deindent();
push(`}`);
}
if (isSlot) {
if ((0, transformSlotPropsDestructuring_1.isDestructuringSlotProps)(isSlot, params)) {
push('}');
}
push(`)`);
}
}
const booleanBinExprOperators = ['==', '===', '!=', '!==', '<', '>', '<=', '>='];
function shouldWrapperConditionalTest(test, context) {
const isSimpleExpr = (0, uni_cli_shared_1.isSimpleExpressionNode)(test);
if (isSimpleExpr) {
const { content } = test;
if (content === 'true' || content === 'false') {
return false;
}
}
if (isSimpleExpr || (0, uni_cli_shared_1.isCompoundExpressionNode)(test)) {
const code = (0, transformExpression_1.stringifyExpression)(test);
const ast = (0, parser_1.parseExpression)(code, {
plugins: context.expressionPlugins,
});
if ((0, types_1.isBinaryExpression)(ast)) {
// 先简易解析
if (booleanBinExprOperators.includes(ast.operator)) {
return false;
}
}
}
return true;
}
function genConditionalExpression(node, context) {
const { test, consequent, alternate, newline: needNewline } = node;
const { push, indent, deindent, newline } = context;
const wrapper = shouldWrapperConditionalTest(test, context);
wrapper && push(`${context.helper(runtimeHelpers_1.IS_TRUE)}(`);
if (test.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
genExpression(test, context);
}
else {
genNode(test, context);
}
wrapper && push(`)`);
needNewline && indent();
context.indentLevel++;
needNewline || push(` `);
push(`? `);
genNode(consequent, context);
context.indentLevel--;
needNewline && newline();
needNewline || push(` `);
push(`: `);
const isNested = alternate.type === compiler_core_1.NodeTypes.JS_CONDITIONAL_EXPRESSION;
if (!isNested) {
context.indentLevel++;
}
genNode(alternate, context);
if (!isNested) {
context.indentLevel--;
}
needNewline && deindent(true /* without newline */);
}
function genCacheExpression(node, context) {
const { push, helper, indent, deindent, newline } = context;
push(`${compiler_core_1.helperNameMap[runtimeHelpers_1.RESOLVE_CACHE]}(_cache, ${node.index}, (): VNode => {`);
if (node.isVNode) {
indent();
push(`${helper(compiler_core_1.SET_BLOCK_TRACKING)}(-1)`);
newline();
}
push(`_cache[${node.index}] = `);
genNode(node.value, context);
if (node.isVNode) {
newline();
push(`${helper(compiler_core_1.SET_BLOCK_TRACKING)}(1)`);
newline();
push(`return _cache[${node.index}] as VNode`);
deindent();
}
push(`})`);
}
@@ -0,0 +1,73 @@
import type { SourceLocation } from '@vue/compiler-core';
export interface CompilerError extends SyntaxError {
code: number | string;
loc?: SourceLocation;
}
export interface CoreCompilerError extends CompilerError {
code: ErrorCodes;
}
export declare function defaultOnError(error: CompilerError): void;
export declare function defaultOnWarn(msg: CompilerError): void;
export declare function createDOMCompilerError(code: ErrorCodes, loc?: SourceLocation): CoreCompilerError;
type InferCompilerError<T> = T extends ErrorCodes ? CoreCompilerError : CompilerError;
export declare function createCompilerError<T extends number>(code: T, loc?: SourceLocation, messages?: {
[code: number]: string;
}, additionalMessage?: string): InferCompilerError<T>;
export declare const enum ErrorCodes {
ABRUPT_CLOSING_OF_EMPTY_COMMENT = 0,
CDATA_IN_HTML_CONTENT = 1,
DUPLICATE_ATTRIBUTE = 2,
END_TAG_WITH_ATTRIBUTES = 3,
END_TAG_WITH_TRAILING_SOLIDUS = 4,
EOF_BEFORE_TAG_NAME = 5,
EOF_IN_CDATA = 6,
EOF_IN_COMMENT = 7,
EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT = 8,
EOF_IN_TAG = 9,
INCORRECTLY_CLOSED_COMMENT = 10,
INCORRECTLY_OPENED_COMMENT = 11,
INVALID_FIRST_CHARACTER_OF_TAG_NAME = 12,
MISSING_ATTRIBUTE_VALUE = 13,
MISSING_END_TAG_NAME = 14,
MISSING_WHITESPACE_BETWEEN_ATTRIBUTES = 15,
NESTED_COMMENT = 16,
UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME = 17,
UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE = 18,
UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME = 19,
UNEXPECTED_NULL_CHARACTER = 20,
UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME = 21,
UNEXPECTED_SOLIDUS_IN_TAG = 22,
X_INVALID_END_TAG = 23,
X_MISSING_END_TAG = 24,
X_MISSING_INTERPOLATION_END = 25,
X_MISSING_DIRECTIVE_NAME = 26,
X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END = 27,
X_V_IF_NO_EXPRESSION = 28,
X_V_IF_SAME_KEY = 29,
X_V_ELSE_NO_ADJACENT_IF = 30,
X_V_FOR_NO_EXPRESSION = 31,
X_V_FOR_MALFORMED_EXPRESSION = 32,
X_V_FOR_TEMPLATE_KEY_PLACEMENT = 33,
X_V_BIND_NO_EXPRESSION = 34,
X_V_ON_NO_EXPRESSION = 35,
X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET = 36,
X_V_SLOT_MIXED_SLOT_USAGE = 37,
X_V_SLOT_DUPLICATE_SLOT_NAMES = 38,
X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN = 39,
X_V_SLOT_MISPLACED = 40,
X_V_MODEL_NO_EXPRESSION = 41,
X_V_MODEL_MALFORMED_EXPRESSION = 42,
X_V_MODEL_ON_SCOPE_VARIABLE = 43,
X_V_MODEL_ON_PROPS = 44,
X_INVALID_EXPRESSION = 45,
X_KEEP_ALIVE_INVALID_CHILDREN = 46,
X_V_HTML_NO_EXPRESSION = 53,
X_V_HTML_WITH_CHILDREN = 54,
X_PREFIX_ID_NOT_SUPPORTED = 55,
X_MODULE_MODE_NOT_SUPPORTED = 56,
X_CACHE_HANDLER_NOT_SUPPORTED = 57,
X_SCOPE_ID_NOT_SUPPORTED = 58,
__EXTEND_POINT__ = 59
}
export declare const errorMessages: Record<ErrorCodes, string>;
export {};
@@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.errorMessages = exports.createCompilerError = exports.createDOMCompilerError = exports.defaultOnWarn = exports.defaultOnError = void 0;
function defaultOnError(error) {
throw error;
}
exports.defaultOnError = defaultOnError;
function defaultOnWarn(msg) {
console.warn(`[Vue warn] ${msg.message}`);
}
exports.defaultOnWarn = defaultOnWarn;
function createDOMCompilerError(code, loc) {
return createCompilerError(code, loc);
}
exports.createDOMCompilerError = createDOMCompilerError;
function createCompilerError(code, loc, messages, additionalMessage) {
const msg = (messages || exports.errorMessages)[code] + (additionalMessage || ``);
const error = new SyntaxError(String(msg));
error.code = code;
error.loc = loc;
return error;
}
exports.createCompilerError = createCompilerError;
exports.errorMessages = {
// parse errors
[0 /* ErrorCodes.ABRUPT_CLOSING_OF_EMPTY_COMMENT */]: 'Illegal comment.',
[1 /* ErrorCodes.CDATA_IN_HTML_CONTENT */]: 'CDATA section is allowed only in XML context.',
[2 /* ErrorCodes.DUPLICATE_ATTRIBUTE */]: 'Duplicate attribute.',
[3 /* ErrorCodes.END_TAG_WITH_ATTRIBUTES */]: 'End tag cannot have attributes.',
[4 /* ErrorCodes.END_TAG_WITH_TRAILING_SOLIDUS */]: "Illegal '/' in tags.",
[5 /* ErrorCodes.EOF_BEFORE_TAG_NAME */]: 'Unexpected EOF in tag.',
[6 /* ErrorCodes.EOF_IN_CDATA */]: 'Unexpected EOF in CDATA section.',
[7 /* ErrorCodes.EOF_IN_COMMENT */]: 'Unexpected EOF in comment.',
[8 /* ErrorCodes.EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */]: 'Unexpected EOF in script.',
[9 /* ErrorCodes.EOF_IN_TAG */]: 'Unexpected EOF in tag.',
[10 /* ErrorCodes.INCORRECTLY_CLOSED_COMMENT */]: 'Incorrectly closed comment.',
[11 /* ErrorCodes.INCORRECTLY_OPENED_COMMENT */]: 'Incorrectly opened comment.',
[12 /* ErrorCodes.INVALID_FIRST_CHARACTER_OF_TAG_NAME */]: "Illegal tag name. Use '&lt;' to print '<'.",
[13 /* ErrorCodes.MISSING_ATTRIBUTE_VALUE */]: 'Attribute value was expected.',
[14 /* ErrorCodes.MISSING_END_TAG_NAME */]: 'End tag name was expected.',
[15 /* ErrorCodes.MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */]: 'Whitespace was expected.',
[16 /* ErrorCodes.NESTED_COMMENT */]: "Unexpected '<!--' in comment.",
[17 /* ErrorCodes.UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */]: 'Attribute name cannot contain U+0022 ("), U+0027 (\'), and U+003C (<).',
[18 /* ErrorCodes.UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */]: 'Unquoted attribute value cannot contain U+0022 ("), U+0027 (\'), U+003C (<), U+003D (=), and U+0060 (`).',
[19 /* ErrorCodes.UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */]: "Attribute name cannot start with '='.",
[21 /* ErrorCodes.UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */]: "'<?' is allowed only in XML context.",
[20 /* ErrorCodes.UNEXPECTED_NULL_CHARACTER */]: `Unexpected null character.`,
[22 /* ErrorCodes.UNEXPECTED_SOLIDUS_IN_TAG */]: "Illegal '/' in tags.",
// Vue-specific parse errors
[23 /* ErrorCodes.X_INVALID_END_TAG */]: 'Invalid end tag.',
[24 /* ErrorCodes.X_MISSING_END_TAG */]: 'Element is missing end tag.',
[25 /* ErrorCodes.X_MISSING_INTERPOLATION_END */]: 'Interpolation end sign was not found.',
[27 /* ErrorCodes.X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */]: 'End bracket for dynamic directive argument was not found. ' +
'Note that dynamic directive argument cannot contain spaces.',
[26 /* ErrorCodes.X_MISSING_DIRECTIVE_NAME */]: 'Legal directive name was expected.',
// transform errors
[28 /* ErrorCodes.X_V_IF_NO_EXPRESSION */]: `v-if/v-else-if is missing expression.`,
[29 /* ErrorCodes.X_V_IF_SAME_KEY */]: `v-if/else branches must use unique keys.`,
[30 /* ErrorCodes.X_V_ELSE_NO_ADJACENT_IF */]: `v-else/v-else-if has no adjacent v-if or v-else-if.`,
[31 /* ErrorCodes.X_V_FOR_NO_EXPRESSION */]: `v-for is missing expression.`,
[32 /* ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION */]: `v-for has invalid expression.`,
[33 /* ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT */]: `<template v-for> key should be placed on the <template> tag.`,
[34 /* ErrorCodes.X_V_BIND_NO_EXPRESSION */]: `v-bind is missing expression.`,
[35 /* ErrorCodes.X_V_ON_NO_EXPRESSION */]: `v-on is missing expression.`,
[36 /* ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */]: `Unexpected custom directive on <slot> outlet.`,
[37 /* ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE */]: `Mixed v-slot usage on both the component and nested <template>. ` +
`When there are multiple named slots, all slots should use <template> ` +
`syntax to avoid scope ambiguity.`,
[38 /* ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES */]: `Duplicate slot names found. `,
[39 /* ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */]: `Extraneous children found when component already has explicitly named ` +
`default slot. These children will be ignored.`,
[40 /* ErrorCodes.X_V_SLOT_MISPLACED */]: `v-slot can only be used on components or <template> tags.`,
[41 /* ErrorCodes.X_V_MODEL_NO_EXPRESSION */]: `v-model is missing expression.`,
[42 /* ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION */]: `v-model value must be a valid JavaScript member expression.`,
[43 /* ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE */]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
[44 /* ErrorCodes.X_V_MODEL_ON_PROPS */]: `v-model cannot be used on a prop, because local prop bindings are not writable.\nUse a v-bind binding combined with a v-on listener that emits update:x event instead.`,
[45 /* ErrorCodes.X_INVALID_EXPRESSION */]: `Error parsing JavaScript expression: `,
[46 /* ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN */]: `<KeepAlive> expects exactly one child component.`,
[53 /* ErrorCodes.X_V_HTML_NO_EXPRESSION */]: `v-html is missing expression.`,
[54 /* ErrorCodes.X_V_HTML_WITH_CHILDREN */]: `v-html will override element children.`,
// generic errors
[55 /* ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED */]: `"prefixIdentifiers" option is not supported in this build of compiler.`,
[56 /* ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED */]: `ES module mode is not supported in this build of compiler.`,
[57 /* ErrorCodes.X_CACHE_HANDLER_NOT_SUPPORTED */]: `"cacheHandlers" option is only supported when the "prefixIdentifiers" option is enabled.`,
[58 /* ErrorCodes.X_SCOPE_ID_NOT_SUPPORTED */]: `"scopeId" option is only supported in module mode.`,
// just to fulfill types
[59 /* ErrorCodes.__EXTEND_POINT__ */]: ``,
};
@@ -0,0 +1,9 @@
import './runtimeHelpers';
import type { CodegenResult, TemplateCompilerOptions } from './options';
import { type DirectiveTransform, type NodeTransform } from './transform';
export type TransformPreset = [
NodeTransform[],
Record<string, DirectiveTransform>
];
export declare function getBaseTransformPreset(prefixIdentifiers?: boolean): TransformPreset;
export declare function compile(template: string, options: TemplateCompilerOptions): CodegenResult;
@@ -0,0 +1,183 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.compile = exports.getBaseTransformPreset = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const uni_shared_1 = require("@dcloudio/uni-shared");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
require("./runtimeHelpers");
const codegen_1 = require("./codegen");
const transform_1 = require("./transform");
const vIf_1 = require("./transforms/vIf");
const vFor_1 = require("./transforms/vFor");
const vModel_1 = require("./transforms/vModel");
const vShow_1 = require("./transforms/vShow");
const vText_1 = require("./transforms/vText");
const transformInterpolation_1 = require("./transforms/transformInterpolation");
const transformText_1 = require("./transforms/transformText");
const vOnWithModifier_1 = require("./transforms/vOnWithModifier");
const vBind_1 = require("./transforms/vBind");
const transformSlotOutlet_1 = require("./transforms/transformSlotOutlet");
const transformObjectExpression_1 = require("./transforms/transformObjectExpression");
const transformExpression_1 = require("./transforms/transformExpression");
const transformElements_1 = require("./transforms/transformElements");
const transformStyle_1 = require("./transforms/transformStyle");
const vHtml_1 = require("./transforms/vHtml");
const vMemo_1 = require("./transforms/vMemo");
const vOnce_1 = require("./transforms/vOnce");
const source_map_js_1 = require("source-map-js");
const vSlot_1 = require("./transforms/vSlot");
const transformElement_1 = require("./transforms/transformElement");
function getBaseTransformPreset(prefixIdentifiers) {
return [
[
vOnce_1.transformOnce,
vIf_1.transformIf,
vMemo_1.transformMemo,
vFor_1.transformFor,
// order is important
vSlot_1.trackVForSlotScopes,
vHtml_1.transformVHtml,
transformExpression_1.transformExpression,
transformSlotOutlet_1.transformSlotOutlet,
transformElement_1.transformElement,
vSlot_1.trackSlotScopes,
transformText_1.transformText,
uni_cli_shared_1.transformTapToClick,
transformInterpolation_1.transformInterpolation,
transformObjectExpression_1.transformObjectExpression,
transformElements_1.transformElements,
transformStyle_1.transformStyle,
],
{
on: vOnWithModifier_1.transformOn,
bind: vBind_1.transformBind,
model: vModel_1.transformModel,
show: vShow_1.transformShow,
text: vText_1.transformVText,
},
];
}
exports.getBaseTransformPreset = getBaseTransformPreset;
function compile(template, options) {
options.rootDir = options.rootDir || '';
options.targetLanguage = options.targetLanguage || 'kotlin';
options.prefixIdentifiers =
'prefixIdentifiers' in options
? options.prefixIdentifiers
: options.mode === 'module';
wrapOptionsLog(template, options);
const isNativeTag = options?.isNativeTag ||
function (tag) {
return ((0, uni_shared_1.isAppUVueNativeTag)(tag) ||
!!options.parseUTSComponent?.(tag, options.targetLanguage));
};
const ast = (0, compiler_core_1.baseParse)(template, {
comments: false,
isNativeTag,
onError: options.onError,
});
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(options.prefixIdentifiers);
(0, transform_1.transform)(ast, (0, shared_1.extend)({}, options, {
nodeTransforms: [
...nodeTransforms,
...(0, uni_cli_shared_1.getBaseNodeTransforms)('/'),
...(options.nodeTransforms || []), // user transforms
],
directiveTransforms: (0, shared_1.extend)({}, directiveTransforms, options.directiveTransforms || {} // user transforms
),
}));
const result = (0, codegen_1.generate)(ast, options);
// inMap should be the map produced by ./parse.ts which is a simple line-only
// mapping. If it is present, we need to adjust the final map and errors to
// reflect the original line numbers.
if (options.inMap) {
if (options.sourceMap) {
result.map = mapLines(options.inMap, result.map);
}
// if (result.errors.length) {
// patchErrors(errors, source, inMap)
// }
}
return result;
}
exports.compile = compile;
function mapLines(oldMap, newMap) {
if (!oldMap)
return newMap;
if (!newMap)
return oldMap;
const oldMapConsumer = new source_map_js_1.SourceMapConsumer(oldMap);
const newMapConsumer = new source_map_js_1.SourceMapConsumer(newMap);
const mergedMapGenerator = new source_map_js_1.SourceMapGenerator();
newMapConsumer.eachMapping((m) => {
if (m.originalLine == null) {
return;
}
const origPosInOldMap = oldMapConsumer.originalPositionFor({
line: m.originalLine,
column: m.originalColumn ?? 0,
});
if (origPosInOldMap.source == null) {
return;
}
mergedMapGenerator.addMapping({
generated: {
line: m.generatedLine,
column: m.generatedColumn,
},
original: {
line: origPosInOldMap.line, // map line
// use current column, since the oldMap produced by @vue/compiler-sfc
// does not
column: m.originalColumn ?? 0,
},
source: origPosInOldMap.source,
name: origPosInOldMap.name,
});
});
// source-map's type definition is incomplete
const generator = mergedMapGenerator;
oldMapConsumer.sources.forEach((sourceFile) => {
generator._sources.add(sourceFile);
const sourceContent = oldMapConsumer.sourceContentFor(sourceFile);
if (sourceContent != null) {
mergedMapGenerator.setSourceContent(sourceFile, sourceContent);
}
});
generator._sourceRoot = oldMap.sourceRoot;
generator._file = oldMap.file;
return generator.toJSON();
}
function wrapOptionsLog(source, options) {
const { onWarn, onError, inMap } = options;
if (inMap && inMap.sourcesContent?.length) {
if (onWarn || onError) {
const originalSource = inMap.sourcesContent[0];
const offset = originalSource.indexOf(source);
const lineOffset = originalSource.slice(0, offset).split(/\r?\n/).length - 1;
if (onWarn) {
options.onWarn = (err) => {
patchError(err, lineOffset, offset);
onWarn(err);
};
}
if (onError) {
options.onError = (err) => {
patchError(err, lineOffset, offset);
onError(err);
};
}
}
}
}
function patchError(err, lineOffset, offset) {
if (err.loc) {
err.loc.start.line += lineOffset;
err.loc.start.offset += offset;
if (err.loc.end !== err.loc.start) {
err.loc.end.line += lineOffset;
err.loc.end.offset += offset;
}
}
}
@@ -0,0 +1,135 @@
import type { BindingMetadata, CompilerError, RootNode } from '@vue/compiler-core';
import type { TransformPluginContext } from 'rollup';
import type { RawSourceMap } from 'source-map-js';
import type { DirectiveTransform, NodeTransform } from './transform';
interface SharedTransformCodegenOptions {
/**
* @default 'default'
*/
mode?: 'default' | 'module';
rootDir?: string;
targetLanguage?: 'kotlin' | 'swift';
/**
* Transform expressions like {{ foo }} to `_ctx.foo`.
* @default false
*/
prefixIdentifiers?: boolean;
/**
* Optional binding metadata analyzed from script - used to optimize
* binding access when `prefixIdentifiers` is enabled.
*/
bindingMetadata?: BindingMetadata;
/**
* Compile the function for inlining inside setup().
* This allows the function to directly access setup() local bindings.
*/
inline?: boolean;
/**
* Filename for source map generation.
* Also used for self-recursive reference in templates
* @default ''
*/
filename?: string;
/**
* 编译的模板类名
*/
className?: string;
/**
* 解析 uts component 组件
* @param name
* @param type
*/
parseUTSComponent?: (name: string, type: 'kotlin' | 'swift') => {
className: string;
namespace: string;
source: string;
} | undefined | void;
}
export interface CodegenOptions extends SharedTransformCodegenOptions {
inMap?: RawSourceMap;
/**
* Generate source map?
* @default false
*/
sourceMap?: boolean;
/**
* 匹配 easycom 组件
* @param tag
*/
matchEasyCom?: (tag: string, uts: boolean) => string | false | undefined | void;
/**
* template的offset
*/
originalLineOffset?: number;
/**
* script的offset
*/
generatedLineOffset?: number;
}
export interface ErrorHandlingOptions {
onWarn?: (warning: CompilerError) => void;
onError?: (error: CompilerError) => void;
}
export interface TransformOptions extends SharedTransformCodegenOptions, ErrorHandlingOptions {
rootDir?: string;
/**
* Cache v-on handlers to avoid creating new inline functions on each render,
* also avoids the need for dynamically patching the handlers by wrapping it.
* e.g `@click="foo"` by default is compiled to `{ onClick: foo }`. With this
* option it's compiled to:
* ```js
* { onClick: _cache[0] || (_cache[0] = e => _ctx.foo(e)) }
* ```
* - Requires "prefixIdentifiers" to be enabled because it relies on scope
* analysis to determine if a handler is safe to cache.
* @default false
*/
cacheHandlers?: boolean;
/**
* An array of node transforms to be applied to every AST node.
*/
nodeTransforms?: NodeTransform[];
/**
* An object of { name: transform } to be applied to every directive attribute
* node found on element nodes.
*/
directiveTransforms?: Record<string, DirectiveTransform | undefined>;
/**
* If the pairing runtime provides additional built-in elements, use this to
* mark them as built-in so the compiler will generate component vnodes
* for them.
*/
isBuiltInComponent?: (tag: string) => symbol | void;
/**
* Used by some transforms that expects only native elements
*/
isCustomElement?: (tag: string) => boolean | void;
/**
* SFC scoped styles ID
*/
scopeId?: string | null;
/**
* Indicates this SFC template has used :slotted in its styles
* Defaults to `true` for backwards compatibility - SFC tooling should set it
* to `false` if no `:slotted` usage is detected in `<style>`
*/
slotted?: boolean;
}
export type TemplateCompilerOptions = {
/**
* e.g. platform native elements, e.g. `<div>` for browsers
*/
isNativeTag?: (tag: string) => boolean;
preprocessLang?: string;
preprocessOptions?: any;
pluginContext?: TransformPluginContext;
} & TransformOptions & CodegenOptions;
export interface CodegenResult {
ast?: RootNode;
code: string;
preamble?: string;
easyComponentAutoImports: Record<string, [string, string]>;
elements: string[];
map?: RawSourceMap;
}
export {};
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
export declare const IS_TRUE: unique symbol;
export declare const V_SHOW: unique symbol;
export declare const RENDER_LIST: unique symbol;
export declare const FRAGMENT: unique symbol;
export declare const OPEN_BLOCK: unique symbol;
export declare const RESOLVE_COMPONENT: unique symbol;
export declare const RESOLVE_DIRECTIVE: unique symbol;
export declare const RESOLVE_EASY_COMPONENT: unique symbol;
export declare const RENDER_SLOT: unique symbol;
export declare const TO_HANDLERS: unique symbol;
export declare const V_ON_WITH_MODIFIERS: unique symbol;
export declare const WITH_SLOT_CTX: unique symbol;
export declare const WITH_SCOPED_SLOT_CTX: unique symbol;
export declare const RESOLVE_CACHE: unique symbol;
export declare const TRY_SET_REF_VALUE: unique symbol;
export declare const TRY_UPDATE_REF_NUMBER: unique symbol;
export declare const LOOSE_TO_NUMBER: unique symbol;
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LOOSE_TO_NUMBER = exports.TRY_UPDATE_REF_NUMBER = exports.TRY_SET_REF_VALUE = exports.RESOLVE_CACHE = exports.WITH_SCOPED_SLOT_CTX = exports.WITH_SLOT_CTX = exports.V_ON_WITH_MODIFIERS = exports.TO_HANDLERS = exports.RENDER_SLOT = exports.RESOLVE_EASY_COMPONENT = exports.RESOLVE_DIRECTIVE = exports.RESOLVE_COMPONENT = exports.OPEN_BLOCK = exports.FRAGMENT = exports.RENDER_LIST = exports.V_SHOW = exports.IS_TRUE = void 0;
const compiler_core_1 = require("@vue/compiler-core");
exports.IS_TRUE = Symbol(`isTrue`);
exports.V_SHOW = Symbol(`vShow`);
exports.RENDER_LIST = Symbol(`renderList`);
exports.FRAGMENT = Symbol(`Fragment`);
exports.OPEN_BLOCK = Symbol(`openBlock`);
exports.RESOLVE_COMPONENT = Symbol(`resolveComponent`);
exports.RESOLVE_DIRECTIVE = Symbol(`resolveDirective`);
exports.RESOLVE_EASY_COMPONENT = Symbol(`resolveEasyComponent`);
exports.RENDER_SLOT = Symbol(`renderSlot`);
exports.TO_HANDLERS = Symbol(`toHandlers`);
exports.V_ON_WITH_MODIFIERS = Symbol(`vOnModifiersGuard`);
exports.WITH_SLOT_CTX = Symbol(`withSlotCtx`);
exports.WITH_SCOPED_SLOT_CTX = Symbol(`withScopedSlotCtx`);
exports.RESOLVE_CACHE = Symbol(`resolveCache`);
exports.TRY_SET_REF_VALUE = Symbol(`trySetRefValue`);
exports.TRY_UPDATE_REF_NUMBER = Symbol(`tryUpdateRefNumber`);
exports.LOOSE_TO_NUMBER = Symbol(`looseToNumber`);
(0, compiler_core_1.registerRuntimeHelpers)({
[exports.IS_TRUE]: 'isTrue',
[exports.V_SHOW]: 'vShow',
[exports.RENDER_LIST]: 'RenderHelpers.renderList',
[exports.FRAGMENT]: 'Fragment',
[exports.RESOLVE_COMPONENT]: 'resolveComponent',
[exports.RESOLVE_EASY_COMPONENT]: 'resolveEasyComponent',
[exports.RESOLVE_DIRECTIVE]: 'resolveDirective',
[exports.RENDER_SLOT]: `renderSlot`,
[exports.TO_HANDLERS]: `toHandlers`,
[exports.V_ON_WITH_MODIFIERS]: `withModifiers`,
[exports.WITH_SLOT_CTX]: `withSlotCtx`,
[exports.WITH_SCOPED_SLOT_CTX]: `withScopedSlotCtx`,
[exports.RESOLVE_CACHE]: `resolveCache`,
[exports.TRY_SET_REF_VALUE]: `trySetRefValue`,
[exports.TRY_UPDATE_REF_NUMBER]: `tryUpdateRefNumber`,
[exports.LOOSE_TO_NUMBER]: `looseToNumber`,
});
@@ -0,0 +1,57 @@
import { type CacheExpression, type ComponentNode, type ConstantTypes, type DirectiveNode, type ElementNode, type ExpressionNode, type JSChildNode, type ParentNode, type PlainElementNode, type Property, type RootNode, type TemplateChildNode, type TemplateLiteral, type TemplateNode } from '@vue/compiler-core';
import type { TransformOptions } from './options';
import type { ParserPlugin } from '@babel/parser';
export type NodeTransform = (node: RootNode | TemplateChildNode, context: TransformContext) => void | (() => void) | (() => void)[];
export type DirectiveTransform = (dir: DirectiveNode, node: ElementNode, context: TransformContext, augmentor?: (ret: DirectiveTransformResult) => DirectiveTransformResult) => DirectiveTransformResult;
export interface DirectiveTransformResult {
props: Property[];
needRuntime?: boolean | symbol;
ssrTagParts?: TemplateLiteral['elements'];
}
export type StructuralDirectiveTransform = (node: ElementNode, dir: DirectiveNode, context: TransformContext) => void | (() => void);
export interface ImportItem {
exp: string | ExpressionNode;
path: string;
}
export interface TransformContext extends Required<Omit<TransformOptions, 'filename' | 'className'>> {
inSSR?: false;
selfName: string | null;
root: RootNode;
helpers: Map<symbol, number>;
components: Set<string>;
directives: Set<string>;
imports: ImportItem[];
temps: number;
cached: number;
identifiers: {
[name: string]: number | undefined;
};
scopes: {
vFor: number;
vSlot: number;
vPre: number;
vOnce: number;
};
parent: ParentNode | null;
childIndex: number;
currentNode: RootNode | TemplateChildNode | null;
inVOnce: boolean;
expressionPlugins: ParserPlugin[];
helper<T extends symbol>(name: T): T;
removeHelper<T extends symbol>(name: T): void;
helperString(name: symbol): string;
replaceNode(node: TemplateChildNode): void;
removeNode(node?: TemplateChildNode): void;
onNodeRemoved(): void;
addIdentifiers(exp: ExpressionNode | string): void;
removeIdentifiers(exp: ExpressionNode | string): void;
cache<T extends JSChildNode>(exp: T, isVNode?: boolean): CacheExpression | T;
constantCache: Map<TemplateChildNode, ConstantTypes>;
elements: Set<string>;
}
export declare function createTransformContext(root: RootNode, { mode, rootDir, targetLanguage, filename, cacheHandlers, prefixIdentifiers, nodeTransforms, directiveTransforms, scopeId, slotted, bindingMetadata, inline, isBuiltInComponent, isCustomElement, onError, onWarn, parseUTSComponent, }: TransformOptions): TransformContext;
export declare function transform(root: RootNode, options: TransformOptions): void;
export declare function isSingleElementRoot(root: RootNode, child: TemplateChildNode): child is PlainElementNode | ComponentNode | TemplateNode;
export declare function traverseChildren(parent: ParentNode, context: TransformContext): void;
export declare function traverseNode(node: RootNode | TemplateChildNode, context: TransformContext): void;
export declare function createStructuralDirectiveTransform(name: string | RegExp, fn: StructuralDirectiveTransform): NodeTransform;
@@ -0,0 +1,310 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createStructuralDirectiveTransform = exports.traverseNode = exports.traverseChildren = exports.isSingleElementRoot = exports.transform = exports.createTransformContext = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const errors_1 = require("./errors");
const runtimeHelpers_1 = require("./runtimeHelpers");
function createTransformContext(root, { mode = 'default', rootDir = '', targetLanguage = 'kotlin', filename = '', cacheHandlers = false, prefixIdentifiers = mode === 'module', nodeTransforms = [], directiveTransforms = {}, scopeId = null, slotted = true, bindingMetadata = shared_1.EMPTY_OBJ, inline = false, isBuiltInComponent = shared_1.NOOP, isCustomElement = shared_1.NOOP, onError = errors_1.defaultOnError, onWarn = errors_1.defaultOnWarn, parseUTSComponent = shared_1.NOOP, }) {
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);
const context = {
// options
mode,
rootDir,
targetLanguage,
selfName: nameMatch && (0, shared_1.capitalize)((0, shared_1.camelize)(nameMatch[1])),
cacheHandlers,
prefixIdentifiers,
bindingMetadata,
inline,
nodeTransforms,
directiveTransforms,
elements: new Set(),
isBuiltInComponent,
isCustomElement,
scopeId,
slotted,
onError,
onWarn,
parseUTSComponent,
// state
root,
helpers: new Map(),
components: new Set(),
directives: new Set(),
imports: [],
constantCache: new Map(),
temps: 0,
cached: 0,
identifiers: Object.create(null),
scopes: {
vFor: 0,
vSlot: 0,
vPre: 0,
vOnce: 0,
},
parent: null,
currentNode: root,
childIndex: 0,
inVOnce: false,
expressionPlugins: ['typescript'],
// methods
helper(name) {
const count = context.helpers.get(name) || 0;
context.helpers.set(name, count + 1);
return name;
},
removeHelper(name) {
const count = context.helpers.get(name);
if (count) {
const currentCount = count - 1;
if (!currentCount) {
context.helpers.delete(name);
}
else {
context.helpers.set(name, currentCount);
}
}
},
helperString(name) {
// return `_${helperNameMap[context.helper(name)]}`
return `${compiler_core_1.helperNameMap[context.helper(name)]}`;
},
replaceNode(node) {
if (!context.currentNode) {
throw new Error(`Node being replaced is already removed.`);
}
if (!context.parent) {
throw new Error(`Cannot replace root node.`);
}
context.parent.children[context.childIndex] = context.currentNode = node;
},
removeNode(node) {
if (!context.parent) {
throw new Error(`Cannot remove root node.`);
}
const list = context.parent.children;
const removalIndex = node
? list.indexOf(node)
: context.currentNode
? context.childIndex
: -1;
/* istanbul ignore if */
if (removalIndex < 0) {
throw new Error(`node being removed is not a child of current parent`);
}
if (!node || node === context.currentNode) {
// current node removed
context.currentNode = null;
context.onNodeRemoved();
}
else {
// sibling node removed
if (context.childIndex > removalIndex) {
context.childIndex--;
context.onNodeRemoved();
}
}
context.parent.children.splice(removalIndex, 1);
},
onNodeRemoved: () => { },
addIdentifiers(exp) {
// identifier tracking only happens in non-browser builds.
if ((0, shared_1.isString)(exp)) {
addId(exp);
}
else if (exp.identifiers) {
exp.identifiers.forEach(addId);
}
else if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
addId(exp.content);
}
},
removeIdentifiers(exp) {
if ((0, shared_1.isString)(exp)) {
removeId(exp);
}
else if (exp.identifiers) {
exp.identifiers.forEach(removeId);
}
else if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
removeId(exp.content);
}
},
cache(exp, isVNode = false) {
return (0, compiler_core_1.createCacheExpression)(context.cached++, exp, isVNode);
},
};
function addId(id) {
const { identifiers } = context;
if (identifiers[id] === undefined) {
identifiers[id] = 0;
}
identifiers[id]++;
}
function removeId(id) {
context.identifiers[id]--;
}
return context;
}
exports.createTransformContext = createTransformContext;
function transform(root, options) {
const context = createTransformContext(root, options);
traverseNode(root, context);
createRootCodegen(root, context);
// finalize meta information
root.helpers = new Set([...context.helpers.keys()]);
root.components = [...context.components];
root.directives = [...context.directives];
root.imports = context.imports;
// root.hoists = context.hoists
root.temps = context.temps;
root.cached = context.cached;
// @ts-expect-error
root.elements = Array.from(context.elements);
}
exports.transform = transform;
function isSingleElementRoot(root, child) {
const { children } = root;
return (children.length === 1 &&
child.type === compiler_core_1.NodeTypes.ELEMENT &&
!(0, compiler_core_1.isSlotOutlet)(child));
}
exports.isSingleElementRoot = isSingleElementRoot;
function createRootCodegen(root, context) {
const { helper } = context;
const { children } = root;
if (children.length === 1) {
const child = children[0];
// if the single child is an element, turn it into a block.
if (isSingleElementRoot(root, child) && child.codegenNode) {
// single element root is never hoisted so codegenNode will never be
// SimpleExpressionNode
const codegenNode = child.codegenNode;
if (codegenNode.type === compiler_core_1.NodeTypes.VNODE_CALL) {
(0, compiler_core_1.convertToBlock)(codegenNode, context);
}
root.codegenNode = codegenNode;
}
else {
// - single <slot/>, IfNode, ForNode: already blocks.
// - single text node: always patched.
// root codegen falls through via genNode()
root.codegenNode = child;
}
}
else if (children.length > 1) {
// root has multiple nodes - return a fragment block.
let patchFlag = shared_1.PatchFlags.STABLE_FRAGMENT;
let patchFlagText = shared_1.PatchFlagNames[shared_1.PatchFlags.STABLE_FRAGMENT];
// check if the fragment actually contains a single valid child with
// the rest being comments
if (children.filter((c) => c.type !== compiler_core_1.NodeTypes.COMMENT).length === 1) {
patchFlag |= shared_1.PatchFlags.DEV_ROOT_FRAGMENT;
patchFlagText += `, ${shared_1.PatchFlagNames[shared_1.PatchFlags.DEV_ROOT_FRAGMENT]}`;
}
root.codegenNode = (0, compiler_core_1.createVNodeCall)(
// @ts-expect-error
context, helper(runtimeHelpers_1.FRAGMENT), undefined, root.children, patchFlag + ` /* ${patchFlagText} */`, undefined, undefined, true, undefined, false /* isComponent */);
}
else {
// no children = noop. codegen will return null.
}
}
function traverseChildren(parent, context) {
let i = 0;
const nodeRemoved = () => {
i--;
};
for (; i < parent.children.length; i++) {
const child = parent.children[i];
if ((0, shared_1.isString)(child))
continue;
context.parent = parent;
context.childIndex = i;
context.onNodeRemoved = nodeRemoved;
traverseNode(child, context);
}
}
exports.traverseChildren = traverseChildren;
function traverseNode(node, context) {
context.currentNode = node;
// apply transform plugins
const { nodeTransforms } = context;
const exitFns = [];
for (let i = 0; i < nodeTransforms.length; i++) {
const onExit = nodeTransforms[i](node, context);
if (onExit) {
if ((0, shared_1.isArray)(onExit)) {
exitFns.push(...onExit);
}
else {
exitFns.push(onExit);
}
}
if (!context.currentNode) {
// node was removed
return;
}
else {
// node may have been replaced
node = context.currentNode;
}
}
switch (node.type) {
case compiler_core_1.NodeTypes.COMMENT:
break;
case compiler_core_1.NodeTypes.INTERPOLATION:
break;
// for container types, further traverse downwards
case compiler_core_1.NodeTypes.IF:
for (let i = 0; i < node.branches.length; i++) {
traverseNode(node.branches[i], context);
}
break;
case compiler_core_1.NodeTypes.IF_BRANCH:
case compiler_core_1.NodeTypes.FOR:
case compiler_core_1.NodeTypes.ELEMENT:
case compiler_core_1.NodeTypes.ROOT:
traverseChildren(node, context);
break;
}
// exit transforms
context.currentNode = node;
let i = exitFns.length;
while (i--) {
exitFns[i]();
}
}
exports.traverseNode = traverseNode;
function createStructuralDirectiveTransform(name, fn) {
const matches = (0, shared_1.isString)(name)
? (n) => n === name
: (n) => name.test(n);
return (node, context) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
const { props } = node;
// structural directive transforms are not concerned with slots
// as they are handled separately in vSlot.ts
if (node.tagType === compiler_core_1.ElementTypes.TEMPLATE && props.some(compiler_core_1.isVSlot)) {
return;
}
const exitFns = [];
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (prop.type === compiler_core_1.NodeTypes.DIRECTIVE && matches(prop.name)) {
// structural directives are removed to avoid infinite recursion
// also we remove them *before* applying so that it can further
// traverse itself in case it moves the node around
props.splice(i, 1);
i--;
const onExit = fn(node, prop, context);
if (onExit)
exitFns.push(onExit);
}
}
return exitFns;
}
};
}
exports.createStructuralDirectiveTransform = createStructuralDirectiveTransform;
@@ -0,0 +1,13 @@
import type { NodeTransform, TransformContext } from '../transform';
import { type ArrayExpression, type CallExpression, type ComponentNode, type DirectiveNode, type ElementNode, type ExpressionNode, type ObjectExpression } from '@vue/compiler-core';
export declare const transformElement: NodeTransform;
export declare function resolveComponentType(node: ComponentNode, context: TransformContext, ssr?: boolean): string | symbol | CallExpression;
export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode;
export declare function buildProps(node: ElementNode, context: TransformContext, props: (DirectiveNode | import("@vue/compiler-core").AttributeNode)[] | undefined, isComponent: boolean, isDynamicComponent: boolean, ssr?: boolean): {
props: PropsExpression | undefined;
directives: DirectiveNode[];
patchFlag: number;
dynamicPropNames: string[];
shouldUseBlock: boolean;
};
export declare function buildDirectiveArgs(dir: DirectiveNode, context: TransformContext): ArrayExpression;
@@ -0,0 +1,703 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildDirectiveArgs = exports.buildProps = exports.resolveComponentType = exports.transformElement = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const errors_1 = require("../errors");
const compiler_core_2 = require("@vue/compiler-core");
const compiler_core_3 = require("@vue/compiler-core");
const vSlot_1 = require("./vSlot");
const compiler_core_4 = require("@vue/compiler-core");
const compiler_core_5 = require("@vue/compiler-core");
const compiler_core_6 = require("@vue/compiler-core");
const utils_1 = require("../utils");
// some directive transforms (e.g. v-model) may return a symbol for runtime
// import, which should be used instead of a resolveDirective call.
const directiveImportMap = new WeakMap();
// generate a JavaScript AST for this element's codegen
const transformElement = (node, context) => {
// perform the work on exit, after all child expressions have been
// processed and merged.
return function postTransformElement() {
node = context.currentNode;
if (!(node.type === compiler_core_1.NodeTypes.ELEMENT &&
(node.tagType === compiler_core_1.ElementTypes.ELEMENT ||
node.tagType === compiler_core_1.ElementTypes.COMPONENT))) {
return;
}
const { tag, props } = node;
const isComponent = node.tagType === compiler_core_1.ElementTypes.COMPONENT;
// The goal of the transform is to create a codegenNode implementing the
// VNodeCall interface.
let vnodeTag = isComponent
? resolveComponentType(node, context)
: `"${tag}"`;
const isDynamicComponent = (0, shared_1.isObject)(vnodeTag) && vnodeTag.callee === compiler_core_2.RESOLVE_DYNAMIC_COMPONENT;
let vnodeProps;
let vnodeChildren;
let vnodePatchFlag;
let patchFlag = 0;
let vnodeDynamicProps;
let dynamicPropNames;
let vnodeDirectives;
let shouldUseBlock =
// dynamic component may resolve to plain elements
isDynamicComponent ||
vnodeTag === compiler_core_2.TELEPORT ||
vnodeTag === compiler_core_2.SUSPENSE ||
(!isComponent &&
// <svg> and <foreignObject> must be forced into blocks so that block
// updates inside get proper isSVG flag at runtime. (#639, #643)
// This is technically web-specific, but splitting the logic out of core
// leads to too much unnecessary complexity.
(tag === 'svg' || tag === 'foreignObject'));
// props
if (props.length > 0) {
const propsBuildResult = buildProps(node, context, undefined, isComponent, isDynamicComponent);
vnodeProps = propsBuildResult.props;
patchFlag = propsBuildResult.patchFlag;
dynamicPropNames = propsBuildResult.dynamicPropNames;
const directives = propsBuildResult.directives;
vnodeDirectives =
directives && directives.length
? (0, compiler_core_1.createArrayExpression)(directives.map((dir) => buildDirectiveArgs(dir, context)))
: undefined;
if (propsBuildResult.shouldUseBlock) {
shouldUseBlock = true;
}
}
// children
if (node.children.length > 0) {
if (vnodeTag === compiler_core_2.KEEP_ALIVE) {
// Although a built-in component, we compile KeepAlive with raw children
// instead of slot functions so that it can be used inside Transition
// or other Transition-wrapping HOCs.
// To ensure correct updates with block optimizations, we need to:
// 1. Force keep-alive into a block. This avoids its children being
// collected by a parent block.
shouldUseBlock = true;
// 2. Force keep-alive to always be updated, since it uses raw children.
patchFlag |= shared_1.PatchFlags.DYNAMIC_SLOTS;
if (utils_1.__DEV__ && node.children.length > 1) {
context.onError((0, errors_1.createCompilerError)(46 /* ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN */, {
start: node.children[0].loc.start,
end: node.children[node.children.length - 1].loc.end,
source: '',
}));
}
}
const shouldBuildAsSlots = isComponent &&
// Teleport is not a real component and has dedicated runtime handling
vnodeTag !== compiler_core_2.TELEPORT &&
// explained above.
vnodeTag !== compiler_core_2.KEEP_ALIVE;
if (shouldBuildAsSlots) {
const { slots, hasDynamicSlots } = (0, vSlot_1.buildSlots)(node, context);
vnodeChildren = slots;
if (hasDynamicSlots) {
patchFlag |= shared_1.PatchFlags.DYNAMIC_SLOTS;
}
}
else if (node.children.length === 1 && vnodeTag !== compiler_core_2.TELEPORT) {
const child = node.children[0];
const type = child.type;
// check for dynamic text children
const hasDynamicTextChild = type === compiler_core_1.NodeTypes.INTERPOLATION ||
type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION;
if (hasDynamicTextChild &&
(0, compiler_core_4.getConstantType)(child, context) === compiler_core_1.ConstantTypes.NOT_CONSTANT) {
patchFlag |= shared_1.PatchFlags.TEXT;
}
// pass directly if the only child is a text node
// (plain / interpolation / expression)
if (hasDynamicTextChild || type === compiler_core_1.NodeTypes.TEXT) {
vnodeChildren = child;
}
else {
vnodeChildren = node.children;
}
}
else {
vnodeChildren = node.children;
}
}
// patchFlag & dynamicPropNames
if (patchFlag !== 0) {
if (utils_1.__DEV__) {
if (patchFlag < 0) {
// special flags (negative and mutually exclusive)
vnodePatchFlag =
patchFlag + ` /* ${shared_1.PatchFlagNames[patchFlag]} */`;
}
else {
// bitwise flags
const flagNames = Object.keys(shared_1.PatchFlagNames)
.map(Number)
.filter((n) => n > 0 && patchFlag & n)
.map((n) => shared_1.PatchFlagNames[n])
.join(`, `);
vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;
}
}
else {
vnodePatchFlag = String(patchFlag);
}
if (dynamicPropNames && dynamicPropNames.length) {
vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);
}
}
node.codegenNode = (0, compiler_core_1.createVNodeCall)(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);
};
};
exports.transformElement = transformElement;
function resolveComponentType(node, context, ssr = false) {
let { tag } = node;
// 1. dynamic component
const isExplicitDynamic = isComponentTag(tag);
const isProp = (0, compiler_core_3.findProp)(node, 'is');
if (isProp) {
if (isExplicitDynamic ||
(utils_1.__COMPAT__ &&
(0, utils_1.isCompatEnabled)(compiler_core_6.CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT, context))) {
const exp = isProp.type === compiler_core_1.NodeTypes.ATTRIBUTE
? isProp.value && (0, compiler_core_1.createSimpleExpression)(isProp.value.content, true)
: isProp.exp;
if (exp) {
return (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.RESOLVE_DYNAMIC_COMPONENT), [
exp,
]);
}
}
else if (isProp.type === compiler_core_1.NodeTypes.ATTRIBUTE &&
isProp.value.content.startsWith('vue:')) {
// <button is="vue:xxx">
// if not <component>, only is value that starts with "vue:" will be
// treated as component by the parse phase and reach here, unless it's
// compat mode where all is values are considered components
tag = isProp.value.content.slice(4);
}
}
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
const builtIn = (0, compiler_core_3.isCoreComponent)(tag) || context.isBuiltInComponent(tag);
if (builtIn) {
// built-ins are simply fallthroughs / have special handling during ssr
// so we don't need to import their runtime equivalents
if (!ssr)
context.helper(builtIn);
return builtIn;
}
// 3. user component (from setup bindings)
// this is skipped in browser build since browser builds do not perform
// binding analysis.
if (!utils_1.__BROWSER__) {
const fromSetup = resolveSetupReference(tag, context);
if (fromSetup) {
return fromSetup;
}
const dotIndex = tag.indexOf('.');
if (dotIndex > 0) {
const ns = resolveSetupReference(tag.slice(0, dotIndex), context);
if (ns) {
return ns + tag.slice(dotIndex);
}
}
}
// 4. Self referencing component (inferred from filename)
if (!utils_1.__BROWSER__ &&
context.selfName &&
(0, shared_1.capitalize)((0, shared_1.camelize)(tag)) === context.selfName) {
context.helper(compiler_core_2.RESOLVE_COMPONENT);
// codegen.ts has special check for __self postfix when generating
// component imports, which will pass additional `maybeSelfReference` flag
// to `resolveComponent`.
context.components.add(tag + `__self`);
return (0, compiler_core_3.toValidAssetId)(tag, `component`);
}
// 5. user component (resolve)
context.helper(compiler_core_2.RESOLVE_COMPONENT);
context.components.add(tag);
return (0, compiler_core_3.toValidAssetId)(tag, `component`);
}
exports.resolveComponentType = resolveComponentType;
function resolveSetupReference(name, context) {
const bindings = context.bindingMetadata;
if (!bindings || bindings.__isScriptSetup === false) {
return;
}
const camelName = (0, shared_1.camelize)(name);
const PascalName = (0, shared_1.capitalize)(camelName);
const checkType = (type) => {
if (bindings[name] === type) {
return name;
}
if (bindings[camelName] === type) {
return camelName;
}
if (bindings[PascalName] === type) {
return PascalName;
}
};
const fromConst = checkType(compiler_core_5.BindingTypes.SETUP_CONST) ||
checkType(compiler_core_5.BindingTypes.SETUP_REACTIVE_CONST) ||
checkType(compiler_core_5.BindingTypes.LITERAL_CONST);
if (fromConst) {
return context.inline
? // in inline mode, const setup bindings (e.g. imports) can be used as-is
fromConst
: `$setup[${JSON.stringify(fromConst)}]`;
}
const fromMaybeRef = checkType(compiler_core_5.BindingTypes.SETUP_LET) ||
checkType(compiler_core_5.BindingTypes.SETUP_REF) ||
checkType(compiler_core_5.BindingTypes.SETUP_MAYBE_REF);
if (fromMaybeRef) {
return context.inline
? // setup scope bindings that may be refs need to be unrefed
`${context.helperString(compiler_core_2.UNREF)}(${fromMaybeRef})`
: `$setup[${JSON.stringify(fromMaybeRef)}]`;
}
const fromProps = checkType(compiler_core_5.BindingTypes.PROPS);
if (fromProps) {
return `${context.helperString(compiler_core_2.UNREF)}(${context.inline ? '__props' : '$props'}[${JSON.stringify(fromProps)}])`;
}
}
function buildProps(node, context, props = node.props, isComponent, isDynamicComponent, ssr = false) {
const { tag, loc: elementLoc, children } = node;
let properties = [];
const mergeArgs = [];
const runtimeDirectives = [];
const hasChildren = children.length > 0;
let shouldUseBlock = false;
// patchFlag analysis
let patchFlag = 0;
let hasRef = false;
let hasClassBinding = false;
let hasStyleBinding = false;
let hasHydrationEventBinding = false;
let hasDynamicKeys = false;
let hasVnodeHook = false;
const dynamicPropNames = [];
const pushMergeArg = (arg) => {
if (properties.length) {
mergeArgs.push((0, compiler_core_1.createObjectExpression)(dedupeProperties(properties), elementLoc));
properties = [];
}
if (arg)
mergeArgs.push(arg);
};
const analyzePatchFlag = ({ key, value }) => {
if ((0, compiler_core_3.isStaticExp)(key)) {
const name = key.content;
const isEventHandler = (0, shared_1.isOn)(name);
if (isEventHandler &&
(!isComponent || isDynamicComponent) &&
// omit the flag for click handlers because hydration gives click
// dedicated fast path.
name.toLowerCase() !== 'onclick' &&
// omit v-model handlers
name !== 'onUpdate:modelValue' &&
// omit onVnodeXXX hooks
!(0, shared_1.isReservedProp)(name)) {
hasHydrationEventBinding = true;
}
if (isEventHandler && (0, shared_1.isReservedProp)(name)) {
hasVnodeHook = true;
}
if (isEventHandler && value.type === compiler_core_1.NodeTypes.JS_CALL_EXPRESSION) {
// handler wrapped with internal helper e.g. withModifiers(fn)
// extract the actual expression
value = value.arguments[0];
}
if (value.type === compiler_core_1.NodeTypes.JS_CACHE_EXPRESSION ||
((value.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION ||
value.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) &&
(0, compiler_core_4.getConstantType)(value, context) > 0)) {
// skip if the prop is a cached handler or has constant value
return;
}
if (name === 'ref') {
hasRef = true;
}
else if (name === 'class') {
hasClassBinding = true;
}
else if (name === 'style') {
hasStyleBinding = true;
}
else if (name !== 'key' && !dynamicPropNames.includes(name)) {
dynamicPropNames.push(name);
}
// treat the dynamic class and style binding of the component as dynamic props
if (isComponent &&
(name === 'class' || name === 'style') &&
!dynamicPropNames.includes(name)) {
dynamicPropNames.push(name);
}
}
else {
hasDynamicKeys = true;
}
};
for (let i = 0; i < props.length; i++) {
// static attribute
const prop = props[i];
if (prop.type === compiler_core_1.NodeTypes.ATTRIBUTE) {
const { loc, name, nameLoc, value } = prop;
let isStatic = true;
if (name === 'ref') {
hasRef = true;
if (context.scopes.vFor > 0) {
properties.push((0, compiler_core_1.createObjectProperty)((0, compiler_core_1.createSimpleExpression)('ref_for', true), (0, compiler_core_1.createSimpleExpression)('true')));
}
// in inline mode there is no setupState object, so we can't use string
// keys to set the ref. Instead, we need to transform it to pass the
// actual ref instead.
if (!utils_1.__BROWSER__ && value && context.inline) {
const binding = context.bindingMetadata[value.content];
if (binding === compiler_core_5.BindingTypes.SETUP_LET ||
binding === compiler_core_5.BindingTypes.SETUP_REF ||
binding === compiler_core_5.BindingTypes.SETUP_MAYBE_REF) {
isStatic = false;
properties.push((0, compiler_core_1.createObjectProperty)((0, compiler_core_1.createSimpleExpression)('ref_key', true), (0, compiler_core_1.createSimpleExpression)(value.content, true, value.loc)));
}
}
}
// skip is on <component>, or is="vue:xxx"
if (name === 'is' &&
(isComponentTag(tag) ||
(value && value.content.startsWith('vue:')) ||
(utils_1.__COMPAT__ &&
(0, utils_1.isCompatEnabled)(compiler_core_6.CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT, context)))) {
continue;
}
properties.push((0, compiler_core_1.createObjectProperty)((0, compiler_core_1.createSimpleExpression)(name, true, nameLoc), (0, compiler_core_1.createSimpleExpression)(value ? value.content : '', isStatic, value ? value.loc : loc)));
}
else {
// directives
const { name, arg, exp, loc, modifiers } = prop;
const isVBind = name === 'bind';
const isVOn = name === 'on';
// skip v-slot - it is handled by its dedicated transform.
if (name === 'slot') {
if (!isComponent) {
context.onError((0, errors_1.createCompilerError)(40 /* ErrorCodes.X_V_SLOT_MISPLACED */, loc));
}
continue;
}
// skip v-once/v-memo - they are handled by dedicated transforms.
if (name === 'once' || name === 'memo') {
continue;
}
// skip v-is and :is on <component>
if (name === 'is' ||
(isVBind &&
(0, compiler_core_3.isStaticArgOf)(arg, 'is') &&
(isComponentTag(tag) ||
(utils_1.__COMPAT__ &&
(0, utils_1.isCompatEnabled)(compiler_core_6.CompilerDeprecationTypes.COMPILER_IS_ON_ELEMENT, context))))) {
continue;
}
// skip v-on in SSR compilation
if (isVOn && ssr) {
continue;
}
if (
// #938: elements with dynamic keys should be forced into blocks
(isVBind && (0, compiler_core_3.isStaticArgOf)(arg, 'key')) ||
// inline before-update hooks need to force block so that it is invoked
// before children
(isVOn && hasChildren && (0, compiler_core_3.isStaticArgOf)(arg, 'vue:before-update'))) {
shouldUseBlock = true;
}
if (isVBind && (0, compiler_core_3.isStaticArgOf)(arg, 'ref') && context.scopes.vFor > 0) {
properties.push((0, compiler_core_1.createObjectProperty)((0, compiler_core_1.createSimpleExpression)('ref_for', true), (0, compiler_core_1.createSimpleExpression)('true')));
}
// special case for v-bind and v-on with no argument
if (!arg && (isVBind || isVOn)) {
hasDynamicKeys = true;
if (exp) {
if (isVBind) {
// have to merge early for compat build check
pushMergeArg();
if (utils_1.__COMPAT__) {
// 2.x v-bind object order compat
if (utils_1.__DEV__) {
const hasOverridableKeys = mergeArgs.some((arg) => {
if (arg.type === compiler_core_1.NodeTypes.JS_OBJECT_EXPRESSION) {
return arg.properties.some(({ key }) => {
if (key.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION ||
!key.isStatic) {
return true;
}
return (key.content !== 'class' &&
key.content !== 'style' &&
!(0, shared_1.isOn)(key.content));
});
}
else {
// dynamic expression
return true;
}
});
if (hasOverridableKeys) {
(0, compiler_core_6.checkCompatEnabled)(compiler_core_6.CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER, context, loc);
}
}
if ((0, utils_1.isCompatEnabled)(compiler_core_6.CompilerDeprecationTypes.COMPILER_V_BIND_OBJECT_ORDER, context)) {
mergeArgs.unshift(exp);
continue;
}
}
mergeArgs.push(exp);
}
else {
// v-on="obj" -> toHandlers(obj)
pushMergeArg({
type: compiler_core_1.NodeTypes.JS_CALL_EXPRESSION,
loc,
callee: context.helper(compiler_core_2.TO_HANDLERS),
arguments: isComponent ? [exp] : [exp, `true`],
});
}
}
else {
context.onError((0, errors_1.createCompilerError)(isVBind
? 34 /* ErrorCodes.X_V_BIND_NO_EXPRESSION */
: 35 /* ErrorCodes.X_V_ON_NO_EXPRESSION */, loc));
}
continue;
}
// force hydration for v-bind with .prop modifier
if (isVBind && modifiers.includes('prop')) {
patchFlag |= shared_1.PatchFlags.NEED_HYDRATION;
}
const directiveTransform = context.directiveTransforms[name];
if (directiveTransform) {
// has built-in directive transform.
const { props, needRuntime } = directiveTransform(prop, node, context);
!ssr && props.forEach(analyzePatchFlag);
if (isVOn && arg && !(0, compiler_core_3.isStaticExp)(arg)) {
pushMergeArg((0, compiler_core_1.createObjectExpression)(props, elementLoc));
}
else {
properties.push(...props);
}
if (needRuntime) {
runtimeDirectives.push(prop);
if ((0, shared_1.isSymbol)(needRuntime)) {
directiveImportMap.set(prop, needRuntime);
}
}
}
else if (!(0, shared_1.isBuiltInDirective)(name)) {
// no built-in transform, this is a user custom directive.
runtimeDirectives.push(prop);
// custom dirs may use beforeUpdate so they need to force blocks
// to ensure before-update gets called before children update
if (hasChildren) {
shouldUseBlock = true;
}
}
}
}
let propsExpression = undefined;
// has v-bind="object" or v-on="object", wrap with mergeProps
if (mergeArgs.length) {
// close up any not-yet-merged props
pushMergeArg();
if (mergeArgs.length > 1) {
propsExpression = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.MERGE_PROPS), mergeArgs, elementLoc);
}
else {
// single v-bind with nothing else - no need for a mergeProps call
propsExpression = mergeArgs[0];
}
}
else if (properties.length) {
propsExpression = (0, compiler_core_1.createObjectExpression)(dedupeProperties(properties), elementLoc);
}
// patchFlag analysis
if (hasDynamicKeys) {
patchFlag |= shared_1.PatchFlags.FULL_PROPS;
}
else {
if (hasClassBinding && !isComponent) {
patchFlag |= shared_1.PatchFlags.CLASS;
}
if (hasStyleBinding && !isComponent) {
patchFlag |= shared_1.PatchFlags.STYLE;
}
if (dynamicPropNames.length) {
patchFlag |= shared_1.PatchFlags.PROPS;
}
if (hasHydrationEventBinding) {
patchFlag |= shared_1.PatchFlags.NEED_HYDRATION;
}
}
if (!shouldUseBlock &&
(patchFlag === 0 || patchFlag === shared_1.PatchFlags.NEED_HYDRATION) &&
(hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {
patchFlag |= shared_1.PatchFlags.NEED_PATCH;
}
// pre-normalize props, SSR is skipped for now
if (!context.inSSR && propsExpression) {
switch (propsExpression.type) {
case compiler_core_1.NodeTypes.JS_OBJECT_EXPRESSION:
// means that there is no v-bind,
// but still need to deal with dynamic key binding
let classKeyIndex = -1;
let styleKeyIndex = -1;
let hasDynamicKey = false;
for (let i = 0; i < propsExpression.properties.length; i++) {
const key = propsExpression.properties[i].key;
if ((0, compiler_core_3.isStaticExp)(key)) {
if (key.content === 'class') {
classKeyIndex = i;
}
else if (key.content === 'style') {
styleKeyIndex = i;
}
}
else if (!key.isHandlerKey) {
hasDynamicKey = true;
}
}
const classProp = propsExpression.properties[classKeyIndex];
const styleProp = propsExpression.properties[styleKeyIndex];
// no dynamic key
if (!hasDynamicKey) {
if (classProp && !(0, compiler_core_3.isStaticExp)(classProp.value)) {
classProp.value = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.NORMALIZE_CLASS), [classProp.value]);
}
if (styleProp &&
// the static style is compiled into an object,
// so use `hasStyleBinding` to ensure that it is a dynamic style binding
(hasStyleBinding ||
(styleProp.value.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
styleProp.value.content.trim()[0] === `[`) ||
// v-bind:style and style both exist,
// v-bind:style with static literal object
styleProp.value.type === compiler_core_1.NodeTypes.JS_ARRAY_EXPRESSION)) {
styleProp.value = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.NORMALIZE_STYLE), [styleProp.value]);
}
}
else {
// dynamic key binding, wrap with `normalizeProps`
propsExpression = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.NORMALIZE_PROPS), [propsExpression]);
}
break;
case compiler_core_1.NodeTypes.JS_CALL_EXPRESSION:
// mergeProps call, do nothing
break;
default:
// single v-bind
propsExpression = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.NORMALIZE_PROPS), [
(0, compiler_core_1.createCallExpression)(context.helper(compiler_core_2.GUARD_REACTIVE_PROPS), [
propsExpression,
]),
]);
break;
}
}
return {
props: propsExpression,
directives: runtimeDirectives,
patchFlag,
dynamicPropNames,
shouldUseBlock,
};
}
exports.buildProps = buildProps;
// Dedupe props in an object literal.
// Literal duplicated attributes would have been warned during the parse phase,
// however, it's possible to encounter duplicated `onXXX` handlers with different
// modifiers. We also need to merge static and dynamic class / style attributes.
// - onXXX handlers / style: merge into array
// - class: merge into single expression with concatenation
function dedupeProperties(properties) {
const knownProps = new Map();
const deduped = [];
for (let i = 0; i < properties.length; i++) {
const prop = properties[i];
// dynamic keys are always allowed
if (prop.key.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION || !prop.key.isStatic) {
deduped.push(prop);
continue;
}
const name = prop.key.content;
const existing = knownProps.get(name);
if (existing) {
if (name === 'style' || name === 'class' || (0, shared_1.isOn)(name)) {
mergeAsArray(existing, prop);
}
// unexpected duplicate, should have emitted error during parse
}
else {
knownProps.set(name, prop);
deduped.push(prop);
}
}
return deduped;
}
function mergeAsArray(existing, incoming) {
if (existing.value.type === compiler_core_1.NodeTypes.JS_ARRAY_EXPRESSION) {
existing.value.elements.push(incoming.value);
}
else {
existing.value = (0, compiler_core_1.createArrayExpression)([existing.value, incoming.value], existing.loc);
}
}
function buildDirectiveArgs(dir, context) {
const dirArgs = [];
const runtime = directiveImportMap.get(dir);
if (runtime) {
// built-in directive with runtime
dirArgs.push(context.helperString(runtime));
}
else {
// user directive.
// see if we have directives exposed via <script setup>
const fromSetup = !utils_1.__BROWSER__ && resolveSetupReference('v-' + dir.name, context);
if (fromSetup) {
dirArgs.push(fromSetup);
}
else {
// inject statement for resolving directive
context.helper(compiler_core_2.RESOLVE_DIRECTIVE);
context.directives.add(dir.name);
dirArgs.push((0, compiler_core_3.toValidAssetId)(dir.name, `directive`));
}
}
const { loc } = dir;
if (dir.exp)
dirArgs.push(dir.exp);
if (dir.arg) {
if (!dir.exp) {
dirArgs.push(`void 0`);
}
dirArgs.push(dir.arg);
}
if (Object.keys(dir.modifiers).length) {
if (!dir.arg) {
if (!dir.exp) {
dirArgs.push(`void 0`);
}
dirArgs.push(`void 0`);
}
const trueExpression = (0, compiler_core_1.createSimpleExpression)(`true`, false, loc);
dirArgs.push((0, compiler_core_1.createObjectExpression)(dir.modifiers.map((modifier) => (0, compiler_core_1.createObjectProperty)(modifier, trueExpression)), loc));
}
return (0, compiler_core_1.createArrayExpression)(dirArgs, dir.loc);
}
exports.buildDirectiveArgs = buildDirectiveArgs;
function stringifyDynamicPropNames(props) {
let propsNamesString = `[`;
for (let i = 0, l = props.length; i < l; i++) {
propsNamesString += JSON.stringify(props[i]);
if (i < l - 1)
propsNamesString += ', ';
}
return propsNamesString + `]`;
}
function isComponentTag(tag) {
return tag === 'component' || tag === 'Component';
}
@@ -0,0 +1,3 @@
import { type RootNode, type TemplateChildNode } from '@vue/compiler-core';
import type { TransformContext } from '../transform';
export declare function transformElements(node: RootNode | TemplateChildNode, context: TransformContext): void;
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformElements = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const uni_shared_1 = require("@dcloudio/uni-shared");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
function transformElements(node, context) {
if (node.type === compiler_core_1.NodeTypes.ELEMENT &&
(node.tagType === compiler_core_1.ElementTypes.ELEMENT ||
(node.tagType === compiler_core_1.ElementTypes.COMPONENT &&
(0, uni_shared_1.isAppUVueBuiltInEasyComponent)(node.tag)))) {
context.elements.add(node.tag);
// 原生UTS组件
const utsComponentOptions = context.parseUTSComponent(node.tag, 'kotlin');
if (utsComponentOptions) {
const className = `{ ${(0, uni_cli_shared_1.capitalize)((0, uni_cli_shared_1.camelize)(node.tag)) + 'Component'} }`;
if (!context.imports.find((i) => i.path === utsComponentOptions.source && i.exp === className)) {
context.imports.push({
exp: className,
path: utsComponentOptions.source,
});
}
}
}
}
exports.transformElements = transformElements;
@@ -0,0 +1,5 @@
import type { NodeTransform, TransformContext } from '../transform';
import { type ExpressionNode, type SimpleExpressionNode } from '@vue/compiler-core';
export declare const transformExpression: NodeTransform;
export declare function processExpression(node: SimpleExpressionNode, context: TransformContext, asParams?: boolean, asRawStatements?: boolean, localVars?: Record<string, number>): ExpressionNode;
export declare function stringifyExpression(exp: ExpressionNode | string | (ExpressionNode | string)[]): string;
@@ -0,0 +1,300 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringifyExpression = exports.processExpression = exports.transformExpression = void 0;
const shared_1 = require("@vue/shared");
const parser_1 = require("@babel/parser");
const compiler_core_1 = require("@vue/compiler-core");
const errors_1 = require("../errors");
const runtimeHelpers_1 = require("../runtimeHelpers");
const GLOBALS_WHITE_LISTED = `Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI` +
`,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array` +
`,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt` +
`,console`;
const isGloballyWhitelisted = /*#__PURE__*/ (0, shared_1.makeMap)(GLOBALS_WHITE_LISTED);
const isLiteralWhitelisted = /*#__PURE__*/ (0, shared_1.makeMap)('true,false,null,this');
// a heuristic safeguard to bail constant expressions on presence of
// likely function invocation and member access
const constantBailRE = /\w\s*\(|\.[^\d]/;
const transformExpression = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.INTERPOLATION) {
node.content = processExpression(node.content, context);
}
else if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
// handle directives on element
for (let i = 0; i < node.props.length; i++) {
const dir = node.props[i];
// do not process for v-on & v-for since they are special handled
if (dir.type === compiler_core_1.NodeTypes.DIRECTIVE && dir.name !== 'for') {
const exp = dir.exp;
const arg = dir.arg;
// do not process exp if this is v-on:arg - we need special handling
// for wrapping inline statements.
if (exp &&
exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
!(dir.name === 'on' && arg)) {
dir.exp = processExpression(exp, context,
// slot args must be processed as function params
dir.name === 'slot');
}
if (arg && arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && !arg.isStatic) {
dir.arg = processExpression(arg, context);
}
}
}
}
};
exports.transformExpression = transformExpression;
// Important: since this function uses Node.js only dependencies, it should
// always be used with a leading !__BROWSER__ check so that it can be
// tree-shaken from the browser build.
function processExpression(node, context,
// some expressions like v-slot props & v-for aliases should be parsed as
// function params
asParams = false,
// v-on handler values may contain multiple statements
asRawStatements = false, localVars = Object.create(context.identifiers)) {
if (!context.prefixIdentifiers || !node.content.trim()) {
return node;
}
const { inline, bindingMetadata } = context;
const rewriteIdentifier = (raw, parent, id) => {
const type = (0, shared_1.hasOwn)(bindingMetadata, raw) && bindingMetadata[raw];
if (inline) {
// x = y
const isAssignmentLVal = parent && parent.type === 'AssignmentExpression' && parent.left === id;
// x++
const isUpdateArg = parent && parent.type === 'UpdateExpression' && parent.argument === id;
// ({ x } = y)
const isDestructureAssignment = parent && (0, compiler_core_1.isInDestructureAssignment)(parent, parentStack);
if (isConst(type) ||
type === compiler_core_1.BindingTypes.SETUP_REACTIVE_CONST ||
localVars[raw]) {
return raw;
}
else if (type === compiler_core_1.BindingTypes.SETUP_REF) {
return `${raw}.value`;
}
else if (type === compiler_core_1.BindingTypes.SETUP_MAYBE_REF) {
// const binding that may or may not be ref
// if it's not a ref, then assignments don't make sense -
// so we ignore the non-ref assignment case and generate code
// that assumes the value to be a ref for more efficiency
return isAssignmentLVal || isUpdateArg || isDestructureAssignment
? `${raw}.value`
: `${context.helperString(compiler_core_1.UNREF)}(${raw})`;
}
else if (type === compiler_core_1.BindingTypes.SETUP_LET) {
if (isAssignmentLVal) {
// let binding.
// this is a bit more tricky as we need to cover the case where
// let is a local non-ref value, and we need to replicate the
// right hand side value.
// x = y --> isRef(x) ? x.value = y : x = y
const { right: rVal, operator } = parent;
const rExp = rawExp.slice(rVal.start - 1, rVal.end - 1);
const rExpString = stringifyExpression(processExpression((0, compiler_core_1.createSimpleExpression)(rExp, false), context, false, false, knownIds));
const value = operator === '='
? rExpString
: `${context.helperString(compiler_core_1.UNREF)}(${raw}.also((_)=>{ ${raw} ${operator} ${rExpString} }))`;
return `${context.helperString(compiler_core_1.IS_REF)}(${raw}) ? ${context.helperString(runtimeHelpers_1.TRY_SET_REF_VALUE)}(${raw}, ${value}) : ${raw}`;
}
else if (isUpdateArg) {
// make id replace parent in the code range so the raw update operator
// is removed
id.start = parent.start;
id.end = parent.end;
const { prefix, operator } = parent;
// let binding.
// x++ --> isRef(a) ? a.value++ : a++
return `${type === compiler_core_1.BindingTypes.SETUP_LET ? `${raw} = ` : ''}${context.helperString(runtimeHelpers_1.TRY_UPDATE_REF_NUMBER)}(${raw}, ${operator === '--' ? '-1' : '1'}, ${prefix})`;
}
else if (isDestructureAssignment) {
// TODO
// let binding in a destructure assignment - it's very tricky to
// handle both possible cases here without altering the original
// structure of the code, so we just assume it's not a ref here
// for now
return raw;
}
else {
return `${context.helperString(compiler_core_1.UNREF)}(${raw})`;
}
}
// else if (type === BindingTypes.PROPS) {
// // use __props which is generated by compileScript so in ts mode
// // it gets correct type
// return genPropsAccessExp(raw)
// } else if (type === BindingTypes.PROPS_ALIASED) {
// // prop with a different local alias (from defineProps() destructure)
// return genPropsAccessExp(bindingMetadata.__propsAliases![raw])
// }
}
else {
// if (
// (type && type.startsWith('setup')) ||
// type === BindingTypes.LITERAL_CONST
// ) {
// // setup bindings in non-inline mode
// // return `$setup.${raw}`
// return `$setup.${raw}`
// } else if (type === BindingTypes.PROPS_ALIASED) {
// return `$props['${bindingMetadata.__propsAliases![raw]}']`
// } else if (type) {
// return `$${type}.${raw}`
// }
}
// fallback to ctx
return `_ctx.${raw}`;
};
// fast path if expression is a simple identifier.
const rawExp = node.content;
// bail constant on parens (function invocation) and dot (member access)
const bailConstant = constantBailRE.test(rawExp);
if ((0, compiler_core_1.isSimpleIdentifier)(rawExp)) {
const isScopeVarReference = context.identifiers[rawExp];
const isAllowedGlobal = isGloballyWhitelisted(rawExp);
const isLiteral = isLiteralWhitelisted(rawExp);
if (!asParams &&
!isScopeVarReference &&
!isLiteral &&
(!isAllowedGlobal || bindingMetadata[rawExp])) {
// const bindings exposed from setup can be skipped for patching but
// cannot be hoisted to module scope
if (bindingMetadata[node.content] === compiler_core_1.BindingTypes.SETUP_CONST) {
node.constType = compiler_core_1.ConstantTypes.CAN_SKIP_PATCH;
}
node.content = rewriteIdentifier(rawExp);
}
else if (!isScopeVarReference) {
if (isLiteral) {
node.constType = compiler_core_1.ConstantTypes.CAN_STRINGIFY;
}
else {
node.constType = compiler_core_1.ConstantTypes.CAN_HOIST;
}
}
return node;
}
let ast;
// exp needs to be parsed differently:
// 1. Multiple inline statements (v-on, with presence of `;`): parse as raw
// exp, but make sure to pad with spaces for consistent ranges
// 2. Expressions: wrap with parens (for e.g. object expressions)
// 3. Function arguments (v-for, v-slot): place in a function argument position
const source = asRawStatements
? ` ${rawExp} `
: `(${rawExp})${asParams ? `=>{}` : ``}`;
try {
ast = (0, parser_1.parse)(source, {
plugins: context.expressionPlugins,
}).program;
}
catch (e) {
context.onError((0, errors_1.createCompilerError)(45 /* ErrorCodes.X_INVALID_EXPRESSION */, node.loc, undefined, e.message));
return node;
}
const ids = [];
const parentStack = [];
const knownIds = Object.create(context.identifiers);
(0, compiler_core_1.walkIdentifiers)(ast, (node, parent, _, isReferenced, isLocal) => {
if ((0, compiler_core_1.isStaticPropertyKey)(node, parent)) {
return;
}
const needPrefix = isReferenced && canPrefix(node);
if (needPrefix && !isLocal) {
if ((0, compiler_core_1.isStaticProperty)(parent) && parent.shorthand) {
// property shorthand like { foo }, we need to add the key since
// we rewrite the value
;
node.prefix = `${node.name}: `;
}
node.name = rewriteIdentifier(node.name, parent, node);
ids.push(node);
}
else {
// The identifier is considered constant unless it's pointing to a
// local scope variable (a v-for alias, or a v-slot prop)
if (!(needPrefix && isLocal) && !bailConstant) {
;
node.isConstant = true;
}
// also generate sub-expressions for other identifiers for better
// source map support. (except for property keys which are static)
ids.push(node);
}
}, true, // invoke on ALL identifiers
parentStack, knownIds);
// We break up the compound expression into an array of strings and sub
// expressions (for identifiers that have been prefixed). In codegen, if
// an ExpressionNode has the `.children` property, it will be used instead of
// `.content`.
const children = [];
ids.sort((a, b) => a.start - b.start);
ids.forEach((id, i) => {
// range is offset by -1 due to the wrapping parens when parsed
const start = id.start - 1;
const end = id.end - 1;
const last = ids[i - 1];
const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);
if (leadingText.length || id.prefix) {
children.push(leadingText + (id.prefix || ``));
}
const source = rawExp.slice(start, end);
const child = (0, compiler_core_1.createSimpleExpression)(id.name, false, {
source,
start: (0, compiler_core_1.advancePositionWithClone)(node.loc.start, source, start),
end: (0, compiler_core_1.advancePositionWithClone)(node.loc.start, source, end),
}, id.isConstant ? compiler_core_1.ConstantTypes.CAN_STRINGIFY : compiler_core_1.ConstantTypes.NOT_CONSTANT);
if (id.typeAnnotation?.type === 'TSTypeAnnotation') {
child.content = child.loc.source;
}
children.push(child);
if (i === ids.length - 1 && end < rawExp.length) {
children.push(rawExp.slice(end));
}
});
let ret;
if (children.length) {
ret = (0, compiler_core_1.createCompoundExpression)(children, node.loc);
}
else {
ret = node;
ret.constType = bailConstant
? compiler_core_1.ConstantTypes.NOT_CONSTANT
: compiler_core_1.ConstantTypes.CAN_STRINGIFY;
}
ret.identifiers = Object.keys(knownIds);
return ret;
}
exports.processExpression = processExpression;
function canPrefix(id) {
// skip whitelisted globals
if (isGloballyWhitelisted(id.name)) {
return false;
}
// special case for webpack compilation
if (id.name === 'require') {
return false;
}
return true;
}
function stringifyExpression(exp) {
if ((0, shared_1.isArray)(exp)) {
return exp.map(stringifyExpression).join('');
}
else if ((0, shared_1.isString)(exp)) {
return exp;
}
else if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
return exp.content;
}
else {
return exp.children
.map(stringifyExpression)
.join('');
}
}
exports.stringifyExpression = stringifyExpression;
function isConst(type) {
return (type === compiler_core_1.BindingTypes.SETUP_CONST || type === compiler_core_1.BindingTypes.LITERAL_CONST);
}
@@ -0,0 +1,4 @@
import type { NodeTransform } from '../transform';
import { type InterpolationNode, type TemplateChildNode, type TextNode } from '@vue/compiler-core';
export declare function isText(node: TemplateChildNode): node is TextNode | InterpolationNode;
export declare const transformInterpolation: NodeTransform;
@@ -0,0 +1,106 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformInterpolation = exports.isText = void 0;
const compiler_core_1 = require("@vue/compiler-core");
function isText(node) {
return node.type === compiler_core_1.NodeTypes.INTERPOLATION || node.type === compiler_core_1.NodeTypes.TEXT;
}
exports.isText = isText;
// Merge adjacent text nodes and expressions into a single expression
// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.
const transformInterpolation = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.ROOT ||
node.type === compiler_core_1.NodeTypes.ELEMENT ||
node.type === compiler_core_1.NodeTypes.FOR ||
node.type === compiler_core_1.NodeTypes.IF_BRANCH) {
// perform the transform on node exit so that all expressions have already
// been processed.
return () => {
const children = node.children;
let currentContainer = undefined;
// let hasText = false
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (isText(child)) {
// hasText = true
for (let j = i + 1; j < children.length; j++) {
const next = children[j];
if (isText(next)) {
if (!currentContainer) {
currentContainer = children[i] = (0, compiler_core_1.createCompoundExpression)([child], child.loc);
}
// merge adjacent text node into current
currentContainer.children.push(` + `, next);
children.splice(j, 1);
j--;
}
else {
currentContainer = undefined;
break;
}
}
}
}
// if (
// !hasText ||
// // if this is a plain element with a single text child, leave it
// // as-is since the runtime has dedicated fast path for this by directly
// // setting textContent of the element.
// // for component root it's always normalized anyway.
// (children.length === 1 &&
// (node.type === NodeTypes.ROOT ||
// (node.type === NodeTypes.ELEMENT &&
// node.tagType === ElementTypes.ELEMENT &&
// // #3756
// // custom directives can potentially add DOM elements arbitrarily,
// // we need to avoid setting textContent of the element at runtime
// // to avoid accidentally overwriting the DOM elements added
// // by the user through custom directives.
// !node.props.find(
// p =>
// p.type === NodeTypes.DIRECTIVE &&
// !context.directiveTransforms[p.name]
// ) &&
// // in compat mode, <template> tags with no special directives
// // will be rendered as a fragment so its children must be
// // converted into vnodes.
// (node.tag !== 'template'))))
// ) {
// return
// }
// pre-convert text nodes into createTextVNode(text) calls to avoid
// runtime normalization.
// for (let i = 0; i < children.length; i++) {
// const child = children[i]
// if (isText(child) || child.type === NodeTypes.COMPOUND_EXPRESSION) {
// const callArgs: CallExpression['arguments'] = []
// // createTextVNode defaults to single whitespace, so if it is a
// // single space the code could be an empty call to save bytes.
// if (child.type !== NodeTypes.TEXT || child.content !== ' ') {
// callArgs.push(child)
// }
// // mark dynamic text with flag so it gets patched inside a block
// if (
// !context.ssr &&
// getConstantType(child, context) === ConstantTypes.NOT_CONSTANT
// ) {
// callArgs.push(
// PatchFlags.TEXT +
// (__DEV__ ? ` /* ${PatchFlagNames[PatchFlags.TEXT]} */` : ``)
// )
// }
// children[i] = {
// type: NodeTypes.TEXT_CALL,
// content: child,
// loc: child.loc,
// codegenNode: createCallExpression(
// context.helper(CREATE_TEXT),
// callArgs
// )
// }
// }
// }
};
}
};
exports.transformInterpolation = transformInterpolation;
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformObjectExpression: NodeTransform;
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformObjectExpression = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("../utils");
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const transformObjectExpression = (node, context) => {
// 因为 v-bind without arg 是被 transformElements.ts 直接处理的,没办法在 vBind 中解析处理objectExpression
// 所以 统一在这里拦截处理
const needTransformAttributes = ['style', 'id', 'class', 'nodes'];
return function postTransformObjectExpression() {
node = context.currentNode;
if (!(0, uni_cli_shared_1.isElementNode)(node)) {
return;
}
node.props.forEach((p) => {
if (!(0, uni_cli_shared_1.isDirectiveNode)(p) || !p.exp) {
return;
}
if (p.name === 'bind' && !p.arg) {
// v-bind="{key: value}"
if (p.exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
if (p.exp.content.startsWith('{') && p.exp.content.endsWith('}')) {
p.exp.content = `utsMapOf(${p.exp.content})`;
}
// v-bind="x"
}
else if (p.exp.type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION) {
const children = p.exp.children;
if (children.length > 1 &&
(0, shared_1.isString)(children[0]) &&
(0, shared_1.isString)(children[children.length - 1]) &&
children[0].startsWith('{') &&
children[children.length - 1].endsWith('}')) {
children[0] = `utsMapOf(${children[0]}`;
children[children.length - 1] = `${children[children.length - 1]})`;
}
}
return;
}
if ((p.name === 'bind' &&
needTransformAttributes.includes(p.arg?.content)) ||
p.name === 'on') {
const newExp = (0, utils_1.rewriteObjectExpression)(p.exp, context);
if (newExp) {
p.exp = newExp;
}
}
});
};
};
exports.transformObjectExpression = transformObjectExpression;
@@ -0,0 +1,10 @@
import type { NodeTransform, TransformContext } from '../transform';
import { type ExpressionNode, type SlotOutletNode } from '@vue/compiler-core';
import type { PropsExpression } from '@vue/compiler-core';
export declare const transformSlotOutlet: NodeTransform;
interface SlotOutletProcessResult {
slotName: string | ExpressionNode;
slotProps: PropsExpression | undefined;
}
export declare function processSlotOutlet(node: SlotOutletNode, context: TransformContext): SlotOutletProcessResult;
export {};
@@ -0,0 +1,82 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processSlotOutlet = exports.transformSlotOutlet = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const compiler_core_2 = require("@vue/compiler-core");
const runtimeHelpers_1 = require("../runtimeHelpers");
const shared_1 = require("@vue/shared");
const transformSlotOutlet = (node, context) => {
if ((0, compiler_core_2.isSlotOutlet)(node)) {
const { children, loc } = node;
const { slotName, slotProps } = processSlotOutlet(node, context);
const slotArgs = [
context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,
slotName,
'{}',
'undefined',
'true',
];
let expectedLen = 2;
if (slotProps) {
slotArgs[2] = slotProps;
expectedLen = 3;
}
if (children.length) {
let fn = (0, compiler_core_1.createFunctionExpression)([], children, false, false, loc);
// @ts-expect-error 补充returnType
fn.returnType = `any[]`;
slotArgs[3] = fn;
expectedLen = 4;
}
if (context.scopeId && !context.slotted) {
expectedLen = 5;
}
slotArgs.splice(expectedLen) // remove unused arguments
;
node.codegenNode = (0, compiler_core_1.createCallExpression)(context.helper(runtimeHelpers_1.RENDER_SLOT), slotArgs, loc);
}
};
exports.transformSlotOutlet = transformSlotOutlet;
function processSlotOutlet(node, context) {
let slotName = `"default"`;
let slotProps = undefined;
const nonNameProps = [];
for (let i = 0; i < node.props.length; i++) {
const p = node.props[i];
if (p.type === compiler_core_1.NodeTypes.ATTRIBUTE) {
if (p.value) {
if (p.name === 'name') {
slotName = JSON.stringify(p.value.content);
}
else {
p.name = (0, shared_1.camelize)(p.name);
nonNameProps.push(p);
}
}
}
else {
if (p.name === 'bind' && (0, compiler_core_2.isStaticArgOf)(p.arg, 'name')) {
if (p.exp)
slotName = p.exp;
}
else {
if (p.name === 'bind' && p.arg && (0, compiler_core_2.isStaticExp)(p.arg)) {
p.arg.content = (0, shared_1.camelize)(p.arg.content);
}
nonNameProps.push(p);
}
}
}
if (nonNameProps.length > 0) {
const { props, directives } = (0, compiler_core_1.buildProps)(node, context, nonNameProps, false, false);
slotProps = props;
if (directives.length) {
context.onError((0, compiler_core_1.createCompilerError)(compiler_core_1.ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET, directives[0].loc));
}
}
return {
slotName,
slotProps,
};
}
exports.processSlotOutlet = processSlotOutlet;
@@ -0,0 +1,5 @@
import { type CompoundExpressionNode } from '@vue/compiler-core';
import type { CodegenContext } from '../codegen';
export declare const SLOT_PROPS_NAME = "slotProps";
export declare function isDestructuringSlotProps(isSlot: boolean, params: CompoundExpressionNode): boolean;
export declare function createDestructuringSlotProps(params: CompoundExpressionNode, context: CodegenContext): void;
@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDestructuringSlotProps = exports.isDestructuringSlotProps = exports.SLOT_PROPS_NAME = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
exports.SLOT_PROPS_NAME = 'slotProps';
function isDestructuringSlotProps(isSlot, params) {
if (isSlot && params?.children?.length > 2) {
const firstParam = params.children[0];
const lastParam = params.children[params.children.length - 1];
return ((0, shared_1.isString)(firstParam) &&
firstParam.startsWith('{') &&
(0, shared_1.isString)(lastParam) &&
lastParam.endsWith('}'));
}
return false;
}
exports.isDestructuringSlotProps = isDestructuringSlotProps;
function createDestructuringSlotProps(params, context) {
params.children.forEach((child, index) => {
if (child.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
context.newline();
const content = child.content;
if (isRename(params, index)) {
const originKey = getOriginKey(params.children[index - 1]);
context.push(`const ${content} = ${exports.SLOT_PROPS_NAME}["${originKey}"]`);
}
else if (hasDefaultValue(params, index)) {
const defaultValue = getDefaultValue(params.children[index + 1]);
context.push(`const ${content} = ${exports.SLOT_PROPS_NAME}["${content}"] !== null ? ${exports.SLOT_PROPS_NAME}["${content}"] : ${defaultValue}`);
}
else {
context.push(`const ${content} = ${exports.SLOT_PROPS_NAME}["${content}"]`);
}
}
});
}
exports.createDestructuringSlotProps = createDestructuringSlotProps;
function isRename(params, index) {
const prevChild = params.children[index - 1];
return (0, shared_1.isString)(prevChild) && prevChild.trim().endsWith(':');
}
function getOriginKey(prevChild) {
const originKey = prevChild.substring(0, prevChild.indexOf(':')).trim();
return originKey.startsWith('{') ? originKey.substring(1).trim() : originKey;
}
function hasDefaultValue(params, index) {
const nextChild = params.children[index + 1];
return (0, shared_1.isString)(nextChild) && nextChild.trim().startsWith('=');
}
function getDefaultValue(nextChild) {
const defaultValue = nextChild.trim().substring(1).trim();
return defaultValue.endsWith('}')
? defaultValue.substring(0, defaultValue.length - 1).trim()
: defaultValue;
}
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformStyle: NodeTransform;
@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformStyle = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const uni_nvue_styler_1 = require("@dcloudio/uni-nvue-styler");
const errors_1 = require("../errors");
const shared_1 = require("@vue/shared");
// Verify that the template style is in compliance with specifications
const transformStyle = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
node.props.forEach((p, i) => {
if (p.type === compiler_core_1.NodeTypes.ATTRIBUTE && p.name === 'style' && p.value) {
// 静态 style 编译成对象,减少运行时解析
const styleObjectStr = parseStyleString2ObjectString(p.value.content);
node.props[i] = createVBindStyleExp(styleObjectStr, p.loc);
(0, uni_nvue_styler_1.parse)(p.value.content, {
logLevel: 'WARNING',
map: true,
ts: true,
noCode: true,
type: 'uvue',
platform: process.env.UNI_UTS_PLATFORM,
}).then(({ messages }) => {
messages.forEach((message) => {
context.onWarn((0, errors_1.createCompilerError)(100, p.loc, {
100: message.text,
}));
});
});
}
});
}
};
exports.transformStyle = transformStyle;
function parseStyleString2ObjectString(styleString) {
const styleObject = (0, shared_1.parseStringStyle)(styleString);
return JSON.stringify(styleObject);
}
function createVBindStyleExp(styleObjectStr, loc) {
return {
type: compiler_core_1.NodeTypes.DIRECTIVE,
name: 'bind',
arg: {
type: compiler_core_1.NodeTypes.SIMPLE_EXPRESSION,
content: 'style',
isStatic: true,
constType: 3,
loc: {
end: loc.end,
start: loc.start,
source: 'style',
},
},
exp: {
constType: 0,
content: styleObjectStr,
isStatic: false,
type: compiler_core_1.NodeTypes.SIMPLE_EXPRESSION,
loc: {
end: loc.end,
start: loc.start,
source: styleObjectStr,
},
},
modifiers: [],
loc: {
end: loc.end,
start: loc.start,
source: `:style="${styleObjectStr}"`,
},
};
}
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformText: NodeTransform;
@@ -0,0 +1,84 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformText = void 0;
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const compiler_core_1 = require("@vue/compiler-core");
function isTextNode({ tag }) {
// TODO 临时解决text节点嵌套的问题
return tag === 'text' || tag === 'button';
}
function isTextElement(node) {
return node.type === compiler_core_1.NodeTypes.ELEMENT && node.tag === 'text';
}
function isText(node) {
const { type } = node;
return (type === compiler_core_1.NodeTypes.TEXT ||
type === compiler_core_1.NodeTypes.TEXT_CALL ||
type === compiler_core_1.NodeTypes.INTERPOLATION ||
type === compiler_core_1.NodeTypes.COMPOUND_EXPRESSION);
}
const transformText = (node, _) => {
if (!(0, uni_cli_shared_1.isElementNode)(node)) {
return;
}
if (isTextNode(node)) {
return;
}
const { children } = node;
if (!children.length) {
return;
}
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (isTextElement(child)) {
parseText(child);
}
}
};
exports.transformText = transformText;
/*
1. 转换 \\n 为 \n
2. u-text 下仅支持 slot 及 文本节点
*/
function parseText(node) {
if (node.children.length) {
let firstTextChild;
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
const content = child.content;
if (isText(child) && typeof content === 'string') {
if (!firstTextChild) {
firstTextChild = child;
firstTextChild.content = translateObliqueLine(content);
}
else {
;
firstTextChild.content += translateObliqueLine(content);
node.children.splice(i, 1);
i--;
}
}
else if (child.type === 3) {
node.children.splice(i, 1);
i--;
}
else {
firstTextChild = null;
}
}
}
}
function translateObliqueLine(content) {
const strFragments = content.split('\\n');
return strFragments
.map((str, index) => {
if (index === strFragments.length - 1)
return str;
str += '\\n';
if (!(str.split('\\').length % 2)) {
str = str.replaceAll(/\\n/g, '\n');
}
return str.replaceAll(/\\\\/g, '\\');
})
.join('');
}
@@ -0,0 +1,2 @@
import type { DirectiveTransform } from '../transform';
export declare const transformBind: DirectiveTransform;
@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformBind = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const compiler_core_2 = require("@vue/compiler-core");
const errors_1 = require("../errors");
// v-bind without arg is handled directly in ./transformElements.ts due to it affecting
// codegen for the entire props object. This transform here is only for v-bind
// *with* args.
const transformBind = (dir, _node, context) => {
const { exp, modifiers, loc } = dir;
const arg = dir.arg;
if (arg.type !== compiler_core_2.NodeTypes.SIMPLE_EXPRESSION) {
arg.children.unshift(`(`);
arg.children.push(`) || ""`);
}
else if (!arg.isStatic) {
arg.content = `${arg.content} !== null ? ${arg.content} : ""`;
}
// .sync is replaced by v-model:arg
if (modifiers.includes('camel')) {
if (arg.type === compiler_core_2.NodeTypes.SIMPLE_EXPRESSION) {
if (arg.isStatic) {
arg.content = (0, shared_1.camelize)(arg.content);
}
else {
arg.content = `${context.helperString(compiler_core_1.CAMELIZE)}(${arg.content})`;
}
}
else {
arg.children.unshift(`${context.helperString(compiler_core_1.CAMELIZE)}(`);
arg.children.push(`)`);
}
}
if (!false) {
if (modifiers.includes('prop')) {
injectPrefix(arg, '.');
}
if (modifiers.includes('attr')) {
injectPrefix(arg, '^');
}
}
if (!exp ||
(exp.type === compiler_core_2.NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())) {
context.onError((0, errors_1.createCompilerError)(34 /* ErrorCodes.X_V_BIND_NO_EXPRESSION */, loc));
return {
props: [(0, compiler_core_2.createObjectProperty)(arg, (0, compiler_core_2.createSimpleExpression)('', true, loc))],
};
}
return {
props: [(0, compiler_core_2.createObjectProperty)(arg, exp)],
};
};
exports.transformBind = transformBind;
const injectPrefix = (arg, prefix) => {
if (arg.type === compiler_core_2.NodeTypes.SIMPLE_EXPRESSION) {
if (arg.isStatic) {
arg.content = prefix + arg.content;
}
else {
arg.content = `\`${prefix}\${${arg.content}}\``;
}
}
else {
arg.children.unshift(`'${prefix}' + (`);
arg.children.push(`)`);
}
};
@@ -0,0 +1,13 @@
import { type DirectiveNode, type ElementNode, type ExpressionNode, type ForNode, type SimpleExpressionNode } from '@vue/compiler-core';
import { type TransformContext } from '../transform';
export declare const transformFor: import("../transform").NodeTransform;
export declare function processFor(node: ElementNode, dir: DirectiveNode, context: TransformContext, processCodegen?: (forNode: ForNode) => (() => void) | undefined): (() => void) | undefined;
export interface ForParseResult {
source: ExpressionNode;
value: ExpressionNode | undefined;
key: ExpressionNode | undefined;
index: ExpressionNode | undefined;
finalized: boolean;
}
export declare function parseForExpression(input: SimpleExpressionNode, context: TransformContext): ForParseResult | undefined;
export declare function createForLoopParams({ value, key, index }: ForParseResult, memoArgs: ExpressionNode): ExpressionNode[];
@@ -0,0 +1,321 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createForLoopParams = exports.parseForExpression = exports.processFor = exports.transformFor = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const errors_1 = require("../errors");
const compiler_core_2 = require("@vue/compiler-core");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const runtimeHelpers_1 = require("../runtimeHelpers");
const transformExpression_1 = require("./transformExpression");
// import { validateBrowserExpression } from '../validateExpression'
const shared_1 = require("@vue/shared");
const transform_1 = require("../transform");
const utils_1 = require("../utils");
exports.transformFor = (0, transform_1.createStructuralDirectiveTransform)('for', (node, dir, context) => {
const { helper, removeHelper } = context;
return processFor(node, dir, context, (forNode) => {
// create the loop render function expression now, and add the
// iterator on exit after all children have been traversed
const renderExp = (0, compiler_core_1.createCallExpression)(helper(runtimeHelpers_1.RENDER_LIST), [
forNode.source,
]);
const isTemplate = (0, compiler_core_2.isTemplateNode)(node);
const memo = (0, compiler_core_1.findDir)(node, 'memo');
const keyProp = (0, compiler_core_2.findProp)(node, `key`);
const keyExp = keyProp &&
(keyProp.type === compiler_core_1.NodeTypes.ATTRIBUTE
? (0, compiler_core_1.createSimpleExpression)(keyProp.value.content, true)
: keyProp.exp);
const keyProperty = keyProp ? (0, compiler_core_1.createObjectProperty)(`key`, keyExp) : null;
// if (!__BROWSER__ && isTemplate) {
if (isTemplate) {
// #2085 / #5288 process :key and v-memo expressions need to be
// processed on `<template v-for>`. In this case the node is discarded
// and never traversed so its binding expressions won't be processed
// by the normal transforms.
if (memo) {
memo.exp = (0, transformExpression_1.processExpression)(memo.exp, context);
}
if (keyProperty && keyProp.type !== compiler_core_1.NodeTypes.ATTRIBUTE) {
keyProperty.value = (0, transformExpression_1.processExpression)(keyProperty.value, context);
}
}
const isStableFragment = forNode.source.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
forNode.source.constType > compiler_core_1.ConstantTypes.NOT_CONSTANT;
const fragmentFlag = isStableFragment
? shared_1.PatchFlags.STABLE_FRAGMENT
: keyProp
? shared_1.PatchFlags.KEYED_FRAGMENT
: shared_1.PatchFlags.UNKEYED_FRAGMENT;
forNode.codegenNode = (0, compiler_core_1.createVNodeCall)(context, helper(runtimeHelpers_1.FRAGMENT), undefined, renderExp, fragmentFlag +
// (__DEV__ ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``),
` /* ${shared_1.PatchFlagNames[fragmentFlag]} */`, undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);
return () => {
// finish the codegen now that all children have been traversed
let childBlock;
const { children } = forNode;
// check <template v-for> key placement
// if ((__DEV__ || !__BROWSER__) && isTemplate) {
if (isTemplate) {
node.children.some((c) => {
if (c.type === compiler_core_1.NodeTypes.ELEMENT) {
const key = (0, compiler_core_2.findProp)(c, 'key');
if (key) {
context.onError((0, errors_1.createCompilerError)(33 /* ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));
return true;
}
}
});
}
const needFragmentWrapper = children.length !== 1 || children[0].type !== compiler_core_1.NodeTypes.ELEMENT;
const slotOutlet = (0, compiler_core_2.isSlotOutlet)(node)
? node
: isTemplate &&
node.children.length === 1 &&
(0, compiler_core_2.isSlotOutlet)(node.children[0])
? node.children[0] // api-extractor somehow fails to infer this
: null;
if (slotOutlet) {
// <slot v-for="..."> or <template v-for="..."><slot/></template>
childBlock = slotOutlet.codegenNode;
if (isTemplate && keyProperty) {
// <template v-for="..." :key="..."><slot/></template>
// we need to inject the key to the renderSlot() call.
// the props for renderSlot is passed as the 3rd argument.
(0, compiler_core_2.injectProp)(childBlock, keyProperty, context);
}
}
else if (needFragmentWrapper) {
// <template v-for="..."> with text or multi-elements
// should generate a fragment block for each loop
childBlock = (0, compiler_core_1.createVNodeCall)(context, helper(runtimeHelpers_1.FRAGMENT), keyProperty ? (0, compiler_core_1.createObjectExpression)([keyProperty]) : undefined, node.children, shared_1.PatchFlags.STABLE_FRAGMENT +
// (__DEV__
// ? ` /* ${PatchFlagNames[PatchFlags.STABLE_FRAGMENT]} */`
// : ``),
` /* ${shared_1.PatchFlagNames[shared_1.PatchFlags.STABLE_FRAGMENT]} */`, undefined, undefined, true, undefined, false /* isComponent */);
}
else {
// Normal element v-for. Directly use the child's codegenNode
// but mark it as a block.
childBlock = children[0]
.codegenNode;
if (isTemplate && keyProperty) {
(0, compiler_core_2.injectProp)(childBlock, keyProperty, context);
}
if (childBlock.isBlock !== !isStableFragment) {
if (childBlock.isBlock) {
// switch from block to vnode
removeHelper(runtimeHelpers_1.OPEN_BLOCK);
removeHelper((0, compiler_core_2.getVNodeBlockHelper)(false, childBlock.isComponent));
}
else {
// switch from vnode to block
removeHelper((0, compiler_core_2.getVNodeHelper)(false, childBlock.isComponent));
}
}
childBlock.isBlock = !isStableFragment;
if (childBlock.isBlock) {
helper(runtimeHelpers_1.OPEN_BLOCK);
helper((0, compiler_core_2.getVNodeBlockHelper)(false, childBlock.isComponent));
}
else {
helper((0, compiler_core_2.getVNodeHelper)(false, childBlock.isComponent));
}
}
if (memo) {
const loop = (0, compiler_core_1.createFunctionExpression)(createForLoopParams(forNode.parseResult, (0, compiler_core_1.createSimpleExpression)(`_cached`)));
loop.body = (0, compiler_core_1.createBlockStatement)([
(0, compiler_core_1.createCompoundExpression)([
`const _memo: Array<any | null> = (`,
memo.exp,
`)`,
]),
(0, compiler_core_1.createCompoundExpression)([
`if (_cached != null`,
...(keyExp ? [` && _cached.key === `, keyExp] : []),
` && ${context.helperString(compiler_core_1.IS_MEMO_SAME)}(_cached, _memo)) return _cached`,
]),
(0, compiler_core_1.createCompoundExpression)([`const _item = `, childBlock]),
(0, compiler_core_1.createSimpleExpression)(`_item.memo = _memo`),
(0, compiler_core_1.createSimpleExpression)(`return _item`),
]);
renderExp.arguments.push(loop, (0, compiler_core_1.createSimpleExpression)(`_cache`), (0, compiler_core_1.createSimpleExpression)(String(context.cached++)));
}
else {
renderExp.arguments.push((0, compiler_core_1.createFunctionExpression)(createForLoopParams(forNode.parseResult, (0, compiler_core_1.createSimpleExpression)(`_cached`)), childBlock, true /* force newline */));
}
};
});
});
// target-agnostic transform used for both Client and SSR
function processFor(node, dir, context, processCodegen) {
if (!dir.exp) {
context.onError((0, errors_1.createCompilerError)(31 /* ErrorCodes.X_V_FOR_NO_EXPRESSION */, dir.loc));
return;
}
const parseResult = parseForExpression(
// can only be simple expression because vFor transform is applied
// before expression transform.
dir.exp, context);
if (!parseResult) {
context.onError((0, errors_1.createCompilerError)(32 /* ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));
return;
}
const { addIdentifiers, removeIdentifiers, scopes } = context;
const { source, value, key, index } = parseResult;
if (key === undefined) {
parseResult.key = {
constType: 2,
content: '__key',
isStatic: false,
loc: value?.loc,
type: 4,
};
}
if (index === undefined) {
parseResult.index = {
constType: 2,
content: '__index',
isStatic: false,
loc: value?.loc,
type: 4,
};
}
parseResult.finalized = true;
const forNode = {
type: compiler_core_1.NodeTypes.FOR,
loc: dir.loc,
source,
valueAlias: value,
keyAlias: key,
objectIndexAlias: index,
parseResult,
children: (0, compiler_core_2.isTemplateNode)(node) ? node.children : [node],
};
context.replaceNode(forNode);
// bookkeeping
scopes.vFor++;
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
// scope management
// inject identifiers to context
value && addIdentifiers(value);
key && addIdentifiers(key);
index && addIdentifiers(index);
}
const onExit = processCodegen && processCodegen(forNode);
return () => {
scopes.vFor--;
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
value && removeIdentifiers(value);
key && removeIdentifiers(key);
index && removeIdentifiers(index);
}
if (onExit)
onExit();
};
}
exports.processFor = processFor;
const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
// This regex doesn't cover the case if key or index aliases have destructuring,
// but those do not make sense in the first place, so this works in practice.
const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
const stripParensRE = /^\(|\)$/g;
function parseForExpression(input, context) {
const loc = input.loc;
const exp = input.content;
const inMatch = exp.match(forAliasRE);
if (!inMatch)
return;
const [, LHS, RHS] = inMatch;
const result = {
source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),
value: undefined,
key: undefined,
index: undefined,
finalized: false,
};
if (!utils_1.__BROWSER__ && context.prefixIdentifiers) {
result.source = (0, transformExpression_1.processExpression)(result.source, context);
}
// if (__DEV__ && __BROWSER__) {
// validateBrowserExpression(result.source as SimpleExpressionNode, context)
// }
let valueContent = LHS.trim().replace(stripParensRE, '').trim();
const trimmedOffset = LHS.indexOf(valueContent);
const iteratorMatch = valueContent.match(forIteratorRE);
if (iteratorMatch) {
valueContent = valueContent.replace(forIteratorRE, '').trim();
const keyContent = iteratorMatch[1].trim();
let keyOffset;
if (keyContent) {
keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);
result.key = createAliasExpression(loc, keyContent, keyOffset);
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
result.key = (0, transformExpression_1.processExpression)(result.key, context, true);
}
// if (__DEV__ && __BROWSER__) {
// validateBrowserExpression(
// result.key as SimpleExpressionNode,
// context,
// true
// )
// }
}
if (iteratorMatch[2]) {
const indexContent = iteratorMatch[2].trim();
if (indexContent) {
result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key
? keyOffset + keyContent.length
: trimmedOffset + valueContent.length));
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
result.index = (0, transformExpression_1.processExpression)(result.index, context, true);
}
// if (__DEV__ && __BROWSER__) {
// validateBrowserExpression(
// result.index as SimpleExpressionNode,
// context,
// true
// )
// }
}
}
}
if (valueContent) {
result.value = createAliasExpression(loc, valueContent, trimmedOffset);
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
result.value = (0, transformExpression_1.processExpression)(result.value, context, true);
}
// if (__DEV__ && __BROWSER__) {
// validateBrowserExpression(
// result.value as SimpleExpressionNode,
// context,
// true
// )
// }
}
return result;
}
exports.parseForExpression = parseForExpression;
function createAliasExpression(range, content, offset) {
return (0, compiler_core_1.createSimpleExpression)(content, false, (0, uni_cli_shared_1.getInnerRange)(range, offset, content.length));
}
function createForLoopParams({ value, key, index }, memoArgs) {
return createParamsList([value, key, index, memoArgs]);
}
exports.createForLoopParams = createForLoopParams;
const paramNames = ['__value', '__key', '__item', '_cached'];
function createParamsList(args) {
let i = args.length;
while (i--) {
if (args[i])
break;
}
return args
.slice(0, i + 1)
.map((arg, i) => arg || (0, compiler_core_1.createSimpleExpression)(paramNames[i], false));
}
@@ -0,0 +1,2 @@
import { type NodeTransform } from '@vue/compiler-core';
export declare const transformVHtml: NodeTransform;
@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformVHtml = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const errors_1 = require("../errors");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const transformVHtml = (node, context) => {
if (node.tagType !== compiler_core_1.ElementTypes.ELEMENT) {
return;
}
// check whether bind v-html
if (node.props?.length) {
;
node.props.forEach((prop, index) => {
if (prop.name === 'html' && prop.loc.source.startsWith('v-html=')) {
if (!prop.exp ||
!prop.exp?.content.trim()) {
context.onError((0, errors_1.createDOMCompilerError)(53 /* ErrorCodes.X_V_HTML_NO_EXPRESSION */, prop.loc));
}
if (node.children.length) {
context.onError((0, errors_1.createDOMCompilerError)(54 /* ErrorCodes.X_V_HTML_WITH_CHILDREN */, prop.loc));
}
;
node.children = [
createRichText(node, prop),
];
node.props.splice(index, 1);
}
});
}
};
exports.transformVHtml = transformVHtml;
function createRichText(node, prop) {
return {
tag: 'rich-text',
type: compiler_core_1.NodeTypes.ELEMENT,
tagType: compiler_core_1.ElementTypes.ELEMENT,
props: [(0, uni_cli_shared_1.createBindDirectiveNode)('nodes', prop.exp || '')],
isSelfClosing: true,
children: [],
codegenNode: undefined,
ns: node.ns,
loc: node.loc,
};
}
@@ -0,0 +1,4 @@
import { type DirectiveNode, type ElementNode, type IfBranchNode, type IfNode } from '@vue/compiler-core';
import { type TransformContext } from '../transform';
export declare const transformIf: import("../transform").NodeTransform;
export declare function processIf(node: ElementNode, dir: DirectiveNode, context: TransformContext, processCodegen?: (node: IfNode, branch: IfBranchNode, isRoot: boolean) => (() => void) | undefined): (() => void) | undefined;
@@ -0,0 +1,212 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processIf = exports.transformIf = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const transform_1 = require("../transform");
const errors_1 = require("../errors");
const transformExpression_1 = require("./transformExpression");
exports.transformIf = (0, transform_1.createStructuralDirectiveTransform)(/^(if|else|else-if)$/, (node, dir, context) => {
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
// #1587: We need to dynamically increment the key based on the current
// node's sibling nodes, since chained v-if/else branches are
// rendered at the same depth
const siblings = context.parent.children;
let i = siblings.indexOf(ifNode);
let key = 0;
while (i-- >= 0) {
const sibling = siblings[i];
if (sibling && sibling.type === compiler_core_1.NodeTypes.IF) {
key += sibling.branches.length;
}
}
// Exit callback. Complete the codegenNode when all children have been
// transformed.
return () => {
if (isRoot) {
ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);
}
else {
// attach this branch's codegen node to the v-if root.
const parentCondition = getParentCondition(ifNode.codegenNode);
parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);
}
};
});
});
// target-agnostic transform used for both Client and SSR
function processIf(node, dir, context, processCodegen) {
if (dir.name !== 'else' &&
(!dir.exp || !dir.exp.content.trim())) {
const loc = dir.exp ? dir.exp.loc : node.loc;
context.onError((0, errors_1.createCompilerError)(28 /* ErrorCodes.X_V_IF_NO_EXPRESSION */, dir.loc));
dir.exp = (0, compiler_core_1.createSimpleExpression)(`true`, false, loc);
}
if (context.prefixIdentifiers && dir.exp) {
// dir.exp can only be simple expression because vIf transform is applied
// before expression transform.
dir.exp = (0, transformExpression_1.processExpression)(dir.exp, context);
}
if (dir.name === 'if') {
const branch = createIfBranch(node, dir);
const ifNode = {
type: compiler_core_1.NodeTypes.IF,
loc: node.loc,
branches: [branch],
};
context.replaceNode(ifNode);
if (processCodegen) {
return processCodegen(ifNode, branch, true);
}
}
else {
// locate the adjacent v-if
const siblings = context.parent.children;
let i = siblings.indexOf(node);
while (i-- >= -1) {
const sibling = siblings[i];
if (sibling && sibling.type === compiler_core_1.NodeTypes.COMMENT) {
context.removeNode(sibling);
continue;
}
if (sibling &&
((sibling.type === compiler_core_1.NodeTypes.TEXT && !sibling.content.trim().length) ||
// handle tag text but type = NodeTypes.ELEMENT
(sibling.type === compiler_core_1.NodeTypes.ELEMENT &&
sibling.tag === 'text' &&
!sibling.children[0].content.trim().length))) {
context.removeNode(sibling);
continue;
}
if (sibling && sibling.type === compiler_core_1.NodeTypes.IF) {
// Check if v-else was followed by v-else-if
if (dir.name === 'else-if' &&
sibling.branches[sibling.branches.length - 1].condition === undefined) {
context.onError((0, errors_1.createCompilerError)(30 /* ErrorCodes.X_V_ELSE_NO_ADJACENT_IF */, node.loc));
}
// move the node to the if node's branches
context.removeNode();
const branch = createIfBranch(node, dir);
// check if user is forcing same key on different branches
const key = branch.userKey;
if (key) {
sibling.branches.forEach(({ userKey }) => {
if (isSameKey(userKey, key)) {
context.onError((0, errors_1.createCompilerError)(29 /* ErrorCodes.X_V_IF_SAME_KEY */, branch.userKey.loc));
}
});
}
sibling.branches.push(branch);
const onExit = processCodegen && processCodegen(sibling, branch, false);
// since the branch was removed, it will not be traversed.
// make sure to traverse here.
(0, transform_1.traverseNode)(branch, context);
// call on exit
if (onExit)
onExit();
// make sure to reset currentNode after traversal to indicate this
// node has been removed.
context.currentNode = null;
}
else {
context.onError((0, errors_1.createCompilerError)(30 /* ErrorCodes.X_V_ELSE_NO_ADJACENT_IF */, node.loc));
}
break;
}
}
}
exports.processIf = processIf;
function createIfBranch(node, dir) {
const isTemplateIf = node.tagType === compiler_core_1.ElementTypes.TEMPLATE;
return {
type: compiler_core_1.NodeTypes.IF_BRANCH,
loc: node.loc,
condition: dir.name === 'else' ? undefined : dir.exp,
children: isTemplateIf && !(0, compiler_core_1.findDir)(node, 'for') ? node.children : [node],
userKey: (0, compiler_core_1.findProp)(node, `key`),
isTemplateIf,
};
}
function createCodegenNodeForBranch(branch, keyIndex, context) {
if (branch.condition) {
return (0, compiler_core_1.createConditionalExpression)(branch.condition, createChildrenCodegenNode(branch, keyIndex, context),
// make sure to pass in asBlock: true so that the comment node call
// closes the current block.
(0, compiler_core_1.createCallExpression)(context.helper(compiler_core_1.CREATE_COMMENT), ['"v-if"', 'true']));
}
else {
return createChildrenCodegenNode(branch, keyIndex, context);
}
}
function createChildrenCodegenNode(branch, keyIndex, context) {
const { helper } = context;
const keyProperty = (0, compiler_core_1.createObjectProperty)(`key`, (0, compiler_core_1.createSimpleExpression)(`${keyIndex}`, false, compiler_core_1.locStub, compiler_core_1.ConstantTypes.CAN_HOIST));
const { children } = branch;
const firstChild = children[0];
const needFragmentWrapper = children.length !== 1 || firstChild.type !== compiler_core_1.NodeTypes.ELEMENT;
if (needFragmentWrapper) {
if (children.length === 1 && firstChild.type === compiler_core_1.NodeTypes.FOR) {
// optimize away nested fragments when child is a ForNode
const vnodeCall = firstChild.codegenNode;
(0, compiler_core_1.injectProp)(vnodeCall, keyProperty, context);
return vnodeCall;
}
else {
let patchFlag = shared_1.PatchFlags.STABLE_FRAGMENT;
let patchFlagText = shared_1.PatchFlagNames[shared_1.PatchFlags.STABLE_FRAGMENT];
// check if the fragment actually contains a single valid child with
// the rest being comments
return (0, compiler_core_1.createVNodeCall)(context, helper(compiler_core_1.FRAGMENT), (0, compiler_core_1.createObjectExpression)([keyProperty]), children, patchFlag + ` /* ${patchFlagText} */`, undefined, undefined, true, false, false /* isComponent */, branch.loc);
}
}
else {
const ret = firstChild.codegenNode;
const vnodeCall = (0, compiler_core_1.getMemoedVNodeCall)(ret);
// Change createVNode to createBlock.
if (vnodeCall.type === compiler_core_1.NodeTypes.VNODE_CALL) {
(0, compiler_core_1.convertToBlock)(vnodeCall, context);
}
// inject branch key
(0, compiler_core_1.injectProp)(vnodeCall, keyProperty, context);
return ret;
}
}
function isSameKey(a, b) {
if (!a || a.type !== b.type) {
return false;
}
if (a.type === compiler_core_1.NodeTypes.ATTRIBUTE) {
if (a.value.content !== b.value.content) {
return false;
}
}
else {
// directive
const exp = a.exp;
const branchExp = b.exp;
if (exp.type !== branchExp.type) {
return false;
}
if (exp.type !== compiler_core_1.NodeTypes.SIMPLE_EXPRESSION ||
exp.isStatic !== branchExp.isStatic ||
exp.content !== branchExp.content) {
return false;
}
}
return true;
}
function getParentCondition(node) {
while (true) {
if (node.type === compiler_core_1.NodeTypes.JS_CONDITIONAL_EXPRESSION) {
if (node.alternate.type === compiler_core_1.NodeTypes.JS_CONDITIONAL_EXPRESSION) {
node = node.alternate;
}
else {
return node;
}
}
else if (node.type === compiler_core_1.NodeTypes.JS_CACHE_EXPRESSION) {
node = node.value;
}
}
}
@@ -0,0 +1,4 @@
import { type FunctionExpression, type SourceLocation } from '@vue/compiler-core';
import type { NodeTransform } from '../transform';
export declare const transformMemo: NodeTransform;
export declare function createFunctionExpression(params: FunctionExpression['params'], returns?: FunctionExpression['returns'], newline?: boolean, isSlot?: boolean, loc?: SourceLocation): FunctionExpression;
@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFunctionExpression = exports.transformMemo = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const seen = new WeakSet();
const transformMemo = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
const dir = (0, compiler_core_1.findDir)(node, 'memo');
if (!dir || seen.has(node)) {
return;
}
seen.add(node);
return () => {
const codegenNode = node.codegenNode ||
context.currentNode.codegenNode;
if (codegenNode && codegenNode.type === compiler_core_1.NodeTypes.VNODE_CALL) {
// non-component sub tree should be turned into a block
if (node.tagType !== compiler_core_1.ElementTypes.COMPONENT) {
(0, compiler_core_1.convertToBlock)(codegenNode, context);
}
const fn = createFunctionExpression(undefined, codegenNode);
fn.returnType = 'VNode';
node.codegenNode = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_1.WITH_MEMO), [
dir.exp,
fn,
`_cache`,
String(context.cached++),
]);
}
};
}
};
exports.transformMemo = transformMemo;
function createFunctionExpression(params, returns = undefined, newline = false, isSlot = false, loc = compiler_core_1.locStub) {
return {
type: compiler_core_1.NodeTypes.JS_FUNCTION_EXPRESSION,
params,
returns,
newline,
isSlot,
loc,
};
}
exports.createFunctionExpression = createFunctionExpression;
@@ -0,0 +1,2 @@
import type { DirectiveTransform } from '../transform';
export declare const transformModel: DirectiveTransform;
@@ -0,0 +1,170 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformModel = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const transformExpression_1 = require("./transformExpression");
const estree_walker_1 = require("estree-walker");
const parser_1 = require("@babel/parser");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const errors_1 = require("../errors");
const runtimeHelpers_1 = require("../runtimeHelpers");
const INPUT_TAGS = ['input', 'textarea'];
const AS = ' as ';
const transformModel = (dir, node, context) => {
// 组件 v-model 绑定了复杂表达式,且没有手动 as 类型
if (node.tagType === compiler_core_1.ElementTypes.COMPONENT &&
dir.exp?.children?.length > 1 &&
!dir.loc.source.includes(AS)) {
context.onError((0, errors_1.createCompilerError)(100, dir.loc, {
100: `When custom components use "v-model" to bind complex expressions, you must specify the type using "as", 详见:https://uniapp.dcloud.net.cn/uni-app-x/component/#v-model-complex-expression`,
}));
}
const { exp, arg } = dir;
if (!exp) {
context.onError((0, errors_1.createCompilerError)(41 /* ErrorCodes.X_V_MODEL_NO_EXPRESSION */, dir.loc));
return createTransformProps();
}
let rawExp = exp.loc.source;
let expType = '';
if ((0, uni_cli_shared_1.isCompoundExpressionNode)(exp)) {
if (rawExp.includes(AS)) {
// 目前简单处理(a as string)
if (rawExp.startsWith('(') && rawExp.endsWith(')')) {
rawExp = rawExp.slice(1, -1);
}
const parts = rawExp.split(AS);
rawExp = parts[0].trim();
expType = parts[1].trim();
const source = (0, transformExpression_1.stringifyExpression)(exp);
const ast = (0, parser_1.parseExpression)(source, {
plugins: context.expressionPlugins,
});
let str = '';
(0, estree_walker_1.walk)(ast, {
enter(node) {
if (node.type === 'TSAsExpression') {
str = source.slice(node.expression.start, node.expression.end);
}
},
});
exp.children = [(0, compiler_core_1.createSimpleExpression)(str)];
}
}
const expString = exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp;
// im SFC <script setup> inline mode, the exp may have been transformed into
// _unref(exp)
const bindingType = context.bindingMetadata[rawExp];
// check props
if (bindingType === compiler_core_1.BindingTypes.PROPS ||
bindingType === compiler_core_1.BindingTypes.PROPS_ALIASED) {
context.onError((0, errors_1.createCompilerError)(44 /* ErrorCodes.X_V_MODEL_ON_PROPS */, exp.loc));
return createTransformProps();
}
const maybeRef = context.inline &&
(bindingType === compiler_core_1.BindingTypes.SETUP_LET ||
bindingType === compiler_core_1.BindingTypes.SETUP_REF ||
bindingType === compiler_core_1.BindingTypes.SETUP_MAYBE_REF);
if (!expString.trim() ||
(!(0, compiler_core_1.isMemberExpression)(expString, context) && !maybeRef)) {
context.onError((0, errors_1.createCompilerError)(42 /* ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));
return createTransformProps();
}
if (context.prefixIdentifiers &&
(0, compiler_core_1.isSimpleIdentifier)(expString) &&
context.identifiers[expString]) {
context.onError((0, errors_1.createCompilerError)(43 /* ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE */, exp.loc));
return createTransformProps();
}
const isInputElement = INPUT_TAGS.includes(node.tag);
const propName = arg ? arg : (0, compiler_core_1.createSimpleExpression)('modelValue', true);
let eventName = arg
? (0, compiler_core_1.isStaticExp)(arg)
? `onUpdate:${(0, shared_1.camelize)(arg.content)}`
: (0, compiler_core_1.createCompoundExpression)(['"onUpdate:" + ', arg])
: `onUpdate:modelValue`;
if (isInputElement && eventName === 'onUpdate:modelValue') {
eventName = getEventName(dir);
}
const eventType = isInputElement ? getEventParamsType(dir) : expType;
let eventValue = isInputElement ? `$event.detail.value` : `$event`;
if (withTrim(dir)) {
eventValue = `${eventValue}.trim()`;
}
if (withNumber(dir)) {
eventValue = `${context.helperString(runtimeHelpers_1.LOOSE_TO_NUMBER)}(${eventValue})`;
}
let assignmentExp;
const eventArg = eventType ? `($event: ${eventType})` : `$event`;
if (maybeRef) {
if (bindingType === compiler_core_1.BindingTypes.SETUP_REF) {
// v-model used on known ref.
assignmentExp = (0, compiler_core_1.createCompoundExpression)([
`${eventArg} => {(`,
(0, compiler_core_1.createSimpleExpression)(rawExp, false, exp.loc),
`).value = ${eventValue}}`,
]);
}
else {
// v-model used on a potentially ref binding in <script setup> inline mode.
// the assignment needs to check whether the binding is actually a ref.
// 如果是 const 仅设置值:trySetRefValue(innerValue, `$event`.detail.value)
// 如果是 let 需要执行赋值动作 innerValue = trySetRefValue(innerValue, `$event`.detail.value)
assignmentExp = (0, compiler_core_1.createCompoundExpression)([
`${eventArg} => {${bindingType === compiler_core_1.BindingTypes.SETUP_LET ? `${rawExp} = ` : ''}${context.helperString(runtimeHelpers_1.TRY_SET_REF_VALUE)}(${rawExp}, ${eventValue})}`,
]);
}
}
else {
assignmentExp = (0, compiler_core_1.createCompoundExpression)([
`${eventArg} => {(`,
exp,
`) = ${eventValue}}`,
]);
}
const props = [
// modelValue: foo
(0, compiler_core_1.createObjectProperty)(propName, exp),
// "onUpdate:modelValue": $event => (foo = $event)
(0, compiler_core_1.createObjectProperty)(eventName, assignmentExp),
];
// cache v-model handler if applicable (when it doesn't refer any scope vars)
if (context.prefixIdentifiers &&
!context.inVOnce &&
context.cacheHandlers &&
!(0, compiler_core_1.hasScopeRef)(exp, context.identifiers)) {
props[1].value = context.cache(props[1].value);
}
// modelModifiers: { foo: true, "bar-baz": true }
if (dir.modifiers.length && node.tagType === compiler_core_1.ElementTypes.COMPONENT) {
const modifiers = dir.modifiers
.map((m) => ((0, compiler_core_1.isSimpleIdentifier)(m) ? m : JSON.stringify(m)) + `: true`)
.join(`, `);
const modifiersKey = arg
? (0, compiler_core_1.isStaticExp)(arg)
? `${arg.content}Modifiers`
: (0, compiler_core_1.createCompoundExpression)([arg, ' + "Modifiers"'])
: `modelModifiers`;
props.push((0, compiler_core_1.createObjectProperty)(modifiersKey, (0, compiler_core_1.createSimpleExpression)(`{ ${modifiers} }`, false, dir.loc, compiler_core_1.ConstantTypes.CAN_HOIST)));
}
return createTransformProps(props);
};
exports.transformModel = transformModel;
function createTransformProps(props = []) {
return { props };
}
function getEventName(dir) {
return withLazy(dir) ? 'onBlur' : 'onInput';
}
function getEventParamsType(dir) {
return withLazy(dir) ? 'InputBlurEvent' : 'InputEvent';
}
function withLazy(dir) {
return dir.modifiers.includes('lazy');
}
function withNumber(dir) {
return dir.modifiers.includes('number');
}
function withTrim(dir) {
return dir.modifiers.includes('trim');
}
@@ -0,0 +1,7 @@
import type { DirectiveTransform } from '../transform';
import { type DirectiveNode, type ExpressionNode, type SimpleExpressionNode } from '@vue/compiler-core';
export interface VOnDirectiveNode extends DirectiveNode {
arg: ExpressionNode;
exp: SimpleExpressionNode | undefined;
}
export declare const transformOn: DirectiveTransform;
@@ -0,0 +1,129 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformOn = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const shared_1 = require("@vue/shared");
const errors_1 = require("../errors");
const transformExpression_1 = require("./transformExpression");
const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;
// TODO: inline statement $event type complement
const transformOn = (dir, node, context, augmentor) => {
const { loc, modifiers, arg } = dir;
if (!dir.exp && !modifiers.length) {
context.onError((0, errors_1.createCompilerError)(35 /* ErrorCodes.X_V_ON_NO_EXPRESSION */, loc));
}
let eventName;
if (arg.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
if (arg.isStatic) {
let rawName = arg.content;
// TODO deprecate @vnodeXXX usage
if (rawName.startsWith('vue:')) {
rawName = `vnode-${rawName.slice(4)}`;
}
const eventString = node.tagType !== compiler_core_1.ElementTypes.ELEMENT ||
rawName.startsWith('vnode') ||
!/[A-Z]/.test(rawName)
? // for non-element and vnode lifecycle event listeners, auto convert
// it to camelCase. See issue #2249
(0, shared_1.toHandlerKey)((0, shared_1.camelize)(rawName))
: // preserve case for plain element listeners that have uppercase
// letters, as these may be custom elements' custom events
`on:${rawName}`;
eventName = (0, compiler_core_1.createSimpleExpression)(eventString, true, arg.loc);
}
else {
// #2388
eventName = (0, compiler_core_1.createCompoundExpression)([
`${context.helperString(compiler_core_1.TO_HANDLER_KEY)}(`,
arg,
`)`,
]);
}
}
else {
// already a compound expression.
eventName = arg;
eventName.children.unshift(`${context.helperString(compiler_core_1.TO_HANDLER_KEY)}(`);
eventName.children.push(`)`);
}
// handler processing
let exp = dir.exp;
if (exp && !exp.content.trim()) {
exp = undefined;
}
let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;
if (exp) {
// @ts-expect-error
const isMemberExp = (0, compiler_core_1.isMemberExpression)(exp.content, context);
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));
const hasMultipleStatements = exp.content.includes(`;`);
// process the expression since it's been skipped
if (context.prefixIdentifiers) {
isInlineStatement && context.addIdentifiers(`$event`);
exp = dir.exp = (0, transformExpression_1.processExpression)(exp, context, false, hasMultipleStatements);
isInlineStatement && context.removeIdentifiers(`$event`);
// with scope analysis, the function is hoistable if it has no reference
// to scope variables.
shouldCache =
context.cacheHandlers &&
// unnecessary to cache inside v-once
!context.inVOnce &&
// runtime constants don't need to be cached
// (this is analyzed by compileScript in SFC <script setup>)
!(exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION && exp.constType > 0) &&
// #1541 bail if this is a member exp handler passed to a component -
// we need to use the original function to preserve arity,
// e.g. <transition> relies on checking cb.length to determine
// transition end handling. Inline function is ok since its arity
// is preserved even when cached.
!(isMemberExp && node.tagType === compiler_core_1.ElementTypes.COMPONENT) &&
// bail if the function references closure variables (v-for, v-slot)
// it must be passed fresh to avoid stale values.
!(0, compiler_core_1.hasScopeRef)(exp, context.identifiers);
// If the expression is optimizable and is a member expression pointing
// to a function, turn it into invocation (and wrap in an arrow function
// below) so that it always accesses the latest value when called - thus
// avoiding the need to be patched.
if (shouldCache && isMemberExp) {
if (exp.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
exp.content = `${exp.content} && ${exp.content}(...args)`;
}
else {
exp.children = [...exp.children, ` && `, ...exp.children, `(...args)`];
}
}
}
if (isInlineStatement || (shouldCache && isMemberExp)) {
// wrap inline statement in a function expression
exp = (0, compiler_core_1.createCompoundExpression)([
`${isInlineStatement
? `${loc.source.includes('$event') ? '($event: any)' : '()'}`
: `${``}(...args)`
// } => ${hasMultipleStatements ? `{` : `(`}`,
} => ${`{`}`,
exp,
// hasMultipleStatements ? `}` : `)`
`}`,
]);
}
}
let ret = {
props: [
(0, compiler_core_1.createObjectProperty)(eventName, exp || (0, compiler_core_1.createSimpleExpression)(`() => {}`, false, loc)),
],
};
// apply extended compiler augmentor
if (augmentor) {
ret = augmentor(ret);
}
if (shouldCache) {
// cache handlers so that it's always the same handler being passed down.
// this avoids unnecessary re-renders when users use inline handlers on
// components.
ret.props[0].value = context.cache(ret.props[0].value);
}
// mark the key as handler for props normalization check
ret.props.forEach((p) => (p.key.isHandlerKey = true));
return ret;
};
exports.transformOn = transformOn;
@@ -0,0 +1,2 @@
import type { DirectiveTransform } from '../transform';
export declare const transformOn: DirectiveTransform;
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformOn = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const vOn_1 = require("./vOn");
const runtimeHelpers_1 = require("../runtimeHelpers");
const errors_1 = require("../errors");
const isEventOptionModifier = /*#__PURE__*/ (0, shared_1.makeMap)(`passive,once,capture`);
const isNonKeyModifier = /*#__PURE__*/ (0, shared_1.makeMap)(
// event propagation management
`stop,prevent,self,` +
// system modifiers + exact
`ctrl,shift,alt,meta,exact,` +
// mouse
`middle`);
// left & right could be mouse or key modifiers based on event type
const maybeKeyModifier = /*#__PURE__*/ (0, shared_1.makeMap)('left,right');
const resolveModifiers = (key, modifiers, context, loc) => {
const keyModifiers = [];
const nonKeyModifiers = [];
const eventOptionModifiers = [];
for (let i = 0; i < modifiers.length; i++) {
const modifier = modifiers[i];
if (isEventOptionModifier(modifier)) {
// eventOptionModifiers: modifiers for addEventListener() options,
// e.g. .passive & .capture
if (modifier !== 'once') {
onModifierWarn(modifier, context, loc);
}
else {
eventOptionModifiers.push(modifier);
}
}
else {
// runtimeModifiers: modifiers that needs runtime guards
if (maybeKeyModifier(modifier)) {
onModifierWarn(modifier, context, loc);
}
else {
if (isNonKeyModifier(modifier)) {
if (modifier !== 'stop') {
onModifierWarn(modifier, context, loc);
}
else {
nonKeyModifiers.push(modifier);
}
}
else {
onModifierWarn(modifier, context, loc);
}
}
}
}
return {
keyModifiers,
nonKeyModifiers,
eventOptionModifiers,
};
};
const transformOn = (dir, node, context) => {
return (0, vOn_1.transformOn)(dir, node, context, (baseResult) => {
const { modifiers } = dir;
if (!modifiers.length)
return baseResult;
let { key, value: handlerExp } = baseResult.props[0];
const { nonKeyModifiers, eventOptionModifiers } = resolveModifiers(key, modifiers, context, dir.loc);
if (nonKeyModifiers.length) {
handlerExp = (0, compiler_core_1.createCallExpression)(context.helper(runtimeHelpers_1.V_ON_WITH_MODIFIERS), [
handlerExp,
JSON.stringify(nonKeyModifiers),
]);
}
if (eventOptionModifiers.length) {
const modifierPostfix = eventOptionModifiers.map(shared_1.capitalize).join('');
key = (0, compiler_core_1.isStaticExp)(key)
? (0, compiler_core_1.createSimpleExpression)(`${key.content}${modifierPostfix}`, true)
: (0, compiler_core_1.createCompoundExpression)([`(`, key, `) + "${modifierPostfix}"`]);
}
return {
props: [(0, compiler_core_1.createObjectProperty)(key, handlerExp)],
};
});
};
exports.transformOn = transformOn;
function onModifierWarn(modifier, context, loc) {
context.onWarn((0, errors_1.createCompilerError)(100, loc, {
100: '.' + modifier + ' is not supported',
}));
}
@@ -0,0 +1,2 @@
import type { NodeTransform } from '../transform';
export declare const transformOnce: NodeTransform;
@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformOnce = void 0;
const compiler_core_1 = require("@vue/compiler-core");
const seen = new WeakSet();
const transformOnce = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT && (0, compiler_core_1.findDir)(node, 'once', true)) {
if (seen.has(node) || context.inVOnce) {
return;
}
seen.add(node);
context.inVOnce = true;
context.helper(compiler_core_1.SET_BLOCK_TRACKING);
return () => {
context.inVOnce = false;
const cur = context.currentNode;
if (cur.codegenNode) {
cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);
}
};
}
};
exports.transformOnce = transformOnce;
@@ -0,0 +1,2 @@
import type { DirectiveTransform } from '@vue/compiler-core';
export declare const transformShow: DirectiveTransform;
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformShow = void 0;
const runtimeHelpers_1 = require("../runtimeHelpers");
const transformShow = (dir, node, context) => {
return {
props: [],
needRuntime: context.helper(runtimeHelpers_1.V_SHOW),
};
};
exports.transformShow = transformShow;
@@ -0,0 +1,9 @@
import { type ElementNode, type ExpressionNode, type FunctionExpression, type SlotsExpression, type SourceLocation, type TemplateChildNode } from '@vue/compiler-core';
import type { NodeTransform, TransformContext } from '../transform';
export declare const trackSlotScopes: NodeTransform;
export declare const trackVForSlotScopes: NodeTransform;
export type SlotFnBuilder = (slotProps: ExpressionNode | undefined, slotChildren: TemplateChildNode[], loc: SourceLocation) => FunctionExpression;
export declare function buildSlots(node: ElementNode, context: TransformContext, buildSlotFn?: SlotFnBuilder): {
slots: SlotsExpression;
hasDynamicSlots: boolean;
};
@@ -0,0 +1,283 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSlots = exports.trackVForSlotScopes = exports.trackSlotScopes = void 0;
const shared_1 = require("@vue/shared");
const compiler_core_1 = require("@vue/compiler-core");
const errors_1 = require("../errors");
const vFor_1 = require("./vFor");
const runtimeHelpers_1 = require("../runtimeHelpers");
const utils_1 = require("../utils");
const defaultFallback = (0, compiler_core_1.createSimpleExpression)(`null`, false);
// A NodeTransform that:
// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed
// by transformExpression. This is only applied in non-browser builds with
// { prefixIdentifiers: true }.
// 2. Track v-slot depths so that we know a slot is inside another slot.
// Note the exit callback is executed before buildSlots() on the same node,
// so only nested slots see positive numbers.
const trackSlotScopes = (node, context) => {
if (node.type === compiler_core_1.NodeTypes.ELEMENT &&
(node.tagType === compiler_core_1.ElementTypes.COMPONENT ||
node.tagType === compiler_core_1.ElementTypes.TEMPLATE)) {
// We are only checking non-empty v-slot here
// since we only care about slots that introduce scope variables.
const vSlot = (0, compiler_core_1.findDir)(node, 'slot');
if (vSlot) {
const slotProps = vSlot.exp;
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
slotProps && context.addIdentifiers(slotProps);
}
context.scopes.vSlot++;
return () => {
// if (!__BROWSER__ && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
slotProps && context.removeIdentifiers(slotProps);
}
context.scopes.vSlot--;
};
}
}
};
exports.trackSlotScopes = trackSlotScopes;
// A NodeTransform that tracks scope identifiers for scoped slots with v-for.
// This transform is only applied in non-browser builds with { prefixIdentifiers: true }
const trackVForSlotScopes = (node, context) => {
let vFor;
if ((0, compiler_core_1.isTemplateNode)(node) &&
node.props.some(compiler_core_1.isVSlot) &&
(vFor = (0, compiler_core_1.findDir)(node, 'for'))) {
const result = (vFor.forParseResult = (0, vFor_1.parseForExpression)(vFor.exp, context));
if (result) {
const { value, key, index } = result;
const { addIdentifiers, removeIdentifiers } = context;
value && addIdentifiers(value);
key && addIdentifiers(key);
index && addIdentifiers(index);
return () => {
value && removeIdentifiers(value);
key && removeIdentifiers(key);
index && removeIdentifiers(index);
};
}
}
};
exports.trackVForSlotScopes = trackVForSlotScopes;
const buildClientSlotFn = (props, children, loc) => (0, compiler_core_1.createFunctionExpression)(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);
// Instead of being a DirectiveTransform, v-slot processing is called during
// transformElement to build the slots object for a component.
function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {
context.helper(compiler_core_1.WITH_CTX);
const { children, loc } = node;
const slotsProperties = [];
const dynamicSlots = [];
// If the slot is inside a v-for or another v-slot, force it to be dynamic
// since it likely uses a scope variable.
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;
// with `prefixIdentifiers: true`, this can be further optimized to make
// it dynamic only when the slot actually uses the scope variables.
// if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
if (context.prefixIdentifiers) {
hasDynamicSlots = (0, compiler_core_1.hasScopeRef)(node, context.identifiers);
}
// 1. Check for slot with slotProps on component itself.
// <Comp v-slot="{ prop }"/>
const onComponentSlot = (0, compiler_core_1.findDir)(node, 'slot', true);
if (onComponentSlot) {
const { arg, exp } = onComponentSlot;
if (arg && !(0, compiler_core_1.isStaticExp)(arg)) {
hasDynamicSlots = true;
}
slotsProperties.push((0, compiler_core_1.createObjectProperty)(arg || (0, compiler_core_1.createSimpleExpression)('default', true), buildSlotFn(exp, children, loc)));
}
// 2. Iterate through children and check for template slots
// <template v-slot:foo="{ prop }">
let hasTemplateSlots = false;
let hasNamedDefaultSlot = false;
const implicitDefaultChildren = [];
const seenSlotNames = new Set();
let conditionalBranchIndex = 0;
for (let i = 0; i < children.length; i++) {
const slotElement = children[i];
let slotDir;
if (!(0, compiler_core_1.isTemplateNode)(slotElement) ||
!(slotDir = (0, compiler_core_1.findDir)(slotElement, 'slot', true))) {
// not a <template v-slot>, skip.
if (slotElement.type !== compiler_core_1.NodeTypes.COMMENT) {
implicitDefaultChildren.push(slotElement);
}
continue;
}
if (onComponentSlot) {
// already has on-component slot - this is incorrect usage.
context.onError((0, errors_1.createCompilerError)(37 /* ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));
break;
}
hasTemplateSlots = true;
const { children: slotChildren, loc: slotLoc } = slotElement;
const { arg: slotName = (0, compiler_core_1.createSimpleExpression)(`default`, true), exp: slotProps, loc: dirLoc, } = slotDir;
// check if name is dynamic.
let staticSlotName;
if ((0, compiler_core_1.isStaticExp)(slotName)) {
staticSlotName = slotName ? slotName.content : `default`;
}
else {
hasDynamicSlots = true;
}
const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);
// check if this slot is conditional (v-if/v-for)
let vIf;
let vElse;
let vFor;
if ((vIf = (0, compiler_core_1.findDir)(slotElement, 'if'))) {
hasDynamicSlots = true;
dynamicSlots.push((0, compiler_core_1.createConditionalExpression)(vIf.exp, buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++), defaultFallback));
}
else if ((vElse = (0, compiler_core_1.findDir)(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {
// find adjacent v-if
let j = i;
let prev;
while (j--) {
prev = children[j];
if (prev.type !== compiler_core_1.NodeTypes.COMMENT) {
break;
}
}
if (prev && (0, compiler_core_1.isTemplateNode)(prev) && (0, compiler_core_1.findDir)(prev, 'if')) {
// remove node
children.splice(i, 1);
i--;
// __TEST__ && assert(dynamicSlots.length > 0)
// attach this slot to previous conditional
let conditional = dynamicSlots[dynamicSlots.length - 1];
while (conditional.alternate.type === compiler_core_1.NodeTypes.JS_CONDITIONAL_EXPRESSION) {
conditional = conditional.alternate;
}
conditional.alternate = vElse.exp
? (0, compiler_core_1.createConditionalExpression)(vElse.exp, buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++), defaultFallback)
: buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++);
}
else {
context.onError((0, errors_1.createCompilerError)(30 /* ErrorCodes.X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));
}
}
else if ((vFor = (0, compiler_core_1.findDir)(slotElement, 'for'))) {
hasDynamicSlots = true;
const parseResult = vFor.forParseResult ||
(0, vFor_1.parseForExpression)(vFor.exp, context);
if (parseResult) {
// Render the dynamic slots as an array and add it to the createSlot()
// args. The runtime knows how to handle it appropriately.
dynamicSlots.push((0, compiler_core_1.createCallExpression)(context.helper(runtimeHelpers_1.RENDER_LIST), [
parseResult.source,
(0, compiler_core_1.createFunctionExpression)((0, vFor_1.createForLoopParams)(parseResult, (0, compiler_core_1.createSimpleExpression)(`_cached`)), buildDynamicSlot(slotName, slotFunction), true /* force newline */),
]));
}
else {
context.onError((0, errors_1.createCompilerError)(32 /* ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));
}
}
else {
// check duplicate static names
if (staticSlotName) {
if (seenSlotNames.has(staticSlotName)) {
context.onError((0, errors_1.createCompilerError)(38 /* ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));
continue;
}
seenSlotNames.add(staticSlotName);
if (staticSlotName === 'default') {
hasNamedDefaultSlot = true;
}
}
slotsProperties.push((0, compiler_core_1.createObjectProperty)(slotName, slotFunction));
}
}
if (!onComponentSlot) {
const buildDefaultSlotProperty = (props, children) => {
const fn = buildSlotFn(props, children, loc);
// if (__COMPAT__ && context.compatConfig) {
// fn.isNonScopedSlot = true
// }
return (0, compiler_core_1.createObjectProperty)(`default`, fn);
};
if (!hasTemplateSlots) {
// implicit default slot (on component)
slotsProperties.push(buildDefaultSlotProperty(undefined, children));
}
else if (implicitDefaultChildren.length &&
// #3766
// with whitespace: 'preserve', whitespaces between slots will end up in
// implicitDefaultChildren. Ignore if all implicit children are whitespaces.
implicitDefaultChildren.some((node) => isNonWhitespaceContent(node))) {
// implicit default slot (mixed with named slots)
if (hasNamedDefaultSlot) {
context.onError((0, errors_1.createCompilerError)(39 /* ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));
}
else {
slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));
}
}
}
const slotFlag = hasDynamicSlots
? shared_1.SlotFlags.DYNAMIC
: hasForwardedSlots(node.children)
? shared_1.SlotFlags.FORWARDED
: shared_1.SlotFlags.STABLE;
let slots = (0, compiler_core_1.createObjectExpression)(slotsProperties.concat((0, compiler_core_1.createObjectProperty)(`_`,
// 2 = compiled but dynamic = can skip normalization, but must run diff
// 1 = compiled and static = can skip normalization AND diff as optimized
(0, compiler_core_1.createSimpleExpression)(slotFlag + (utils_1.__DEV__ ? ` /* ${shared_1.slotFlagsText[slotFlag]} */` : ``), false))), loc);
if (dynamicSlots.length) {
slots = (0, compiler_core_1.createCallExpression)(context.helper(compiler_core_1.CREATE_SLOTS), [
slots,
(0, compiler_core_1.createArrayExpression)(dynamicSlots),
]);
}
return {
slots,
hasDynamicSlots,
};
}
exports.buildSlots = buildSlots;
function buildDynamicSlot(name, fn, index) {
const props = [
(0, compiler_core_1.createObjectProperty)(`name`, name),
(0, compiler_core_1.createObjectProperty)(`fn`, fn),
];
if (index != null) {
props.push((0, compiler_core_1.createObjectProperty)(`key`, (0, compiler_core_1.createSimpleExpression)(String(index), true)));
}
return (0, compiler_core_1.createObjectExpression)(props);
}
function hasForwardedSlots(children) {
for (let i = 0; i < children.length; i++) {
const child = children[i];
switch (child.type) {
case compiler_core_1.NodeTypes.ELEMENT:
if (child.tagType === compiler_core_1.ElementTypes.SLOT ||
hasForwardedSlots(child.children)) {
return true;
}
break;
case compiler_core_1.NodeTypes.IF:
if (hasForwardedSlots(child.branches))
return true;
break;
case compiler_core_1.NodeTypes.IF_BRANCH:
case compiler_core_1.NodeTypes.FOR:
if (hasForwardedSlots(child.children))
return true;
break;
default:
break;
}
}
return false;
}
function isNonWhitespaceContent(node) {
if (node.type !== compiler_core_1.NodeTypes.TEXT && node.type !== compiler_core_1.NodeTypes.TEXT_CALL)
return true;
return node.type === compiler_core_1.NodeTypes.TEXT
? !!node.content.trim()
: isNonWhitespaceContent(node.content);
}
@@ -0,0 +1,2 @@
import { type DirectiveTransform } from '@vue/compiler-core';
export declare const transformVText: DirectiveTransform;
@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformVText = void 0;
const compiler_core_1 = require("@vue/compiler-core");
// import { createDOMCompilerError, DOMErrorCodes } from '../errors'
const transformVText = (dir, node, context) => {
const { exp, loc } = dir;
// if (!exp) {
// context.onError(
// createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc)
// )
// }
// if (node.children.length) {
// context.onError(
// createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc)
// )
// node.children.length = 0
// }
return {
props: [
(0, compiler_core_1.createObjectProperty)((0, compiler_core_1.createSimpleExpression)(`value`, true), exp
? (0, compiler_core_1.getConstantType)(exp, context) > 0
? exp
: (0, compiler_core_1.createCallExpression)(context.helperString(compiler_core_1.TO_DISPLAY_STRING), [exp], loc)
: (0, compiler_core_1.createSimpleExpression)('', true)),
],
};
};
exports.transformVText = transformVText;
@@ -0,0 +1,15 @@
import { type ExpressionNode } from '@vue/compiler-core';
import type { TemplateCompilerOptions } from './options';
import type { TransformContext } from './transform';
import type { CompilerError } from './errors';
export declare const __DEV__ = true;
export declare const __BROWSER__ = false;
export declare const __COMPAT__ = false;
export declare function isCompatEnabled(...args: any[]): boolean;
export declare function genRenderFunctionDecl({ className, genDefaultAs, inline, }: TemplateCompilerOptions & {
genDefaultAs?: string;
}): string;
export declare function rewriteObjectExpression(exp: ExpressionNode, context: TransformContext): import("@vue/compiler-core").SimpleExpressionNode | undefined;
export declare function onCompilerError(error: CompilerError): void;
export declare function parseSource(fileName: string, rootDir: string): string;
export declare function addEasyComponentAutoImports(easyComponentAutoImports: Record<string, [string, string]>, rootDir: string, tagName: string, fileName: string): void;
@@ -0,0 +1,86 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addEasyComponentAutoImports = exports.parseSource = exports.onCompilerError = exports.rewriteObjectExpression = exports.genRenderFunctionDecl = exports.isCompatEnabled = exports.__COMPAT__ = exports.__BROWSER__ = exports.__DEV__ = void 0;
const path_1 = __importDefault(require("path"));
const compiler_core_1 = require("@vue/compiler-core");
const estree_walker_1 = require("estree-walker");
const parser_1 = require("@babel/parser");
const magic_string_1 = __importDefault(require("magic-string"));
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const transformExpression_1 = require("./transforms/transformExpression");
exports.__DEV__ = true;
exports.__BROWSER__ = false;
exports.__COMPAT__ = false;
function isCompatEnabled(...args) {
return false;
}
exports.isCompatEnabled = isCompatEnabled;
function genRenderFunctionDecl({ className, genDefaultAs, inline = false, }) {
if (inline) {
return `(): any | null =>`;
}
// 调整返回值类型为 any | null, 支持 <template>some text</template>
const thisCode = genDefaultAs
? `this: InstanceType<typeof ${genDefaultAs}>`
: '';
return `function ${className || ''}Render(${thisCode}): any | null`;
}
exports.genRenderFunctionDecl = genRenderFunctionDecl;
function rewriteObjectExpression(exp, context) {
const source = (0, transformExpression_1.stringifyExpression)(exp);
if (source.includes('{')) {
const s = new magic_string_1.default(source);
const ast = (0, parser_1.parseExpression)(source, {
plugins: context.expressionPlugins,
});
(0, estree_walker_1.walk)(ast, {
enter(node) {
if (node.type === 'ObjectExpression') {
s.prependLeft(node.start, node.properties.length > 0
? 'utsMapOf('
: 'utsMapOf<string, any | null>(');
s.prependRight(node.end, ')');
}
},
});
return (0, compiler_core_1.createSimpleExpression)(s.toString(), false, exp.loc);
}
}
exports.rewriteObjectExpression = rewriteObjectExpression;
function onCompilerError(error) { }
exports.onCompilerError = onCompilerError;
function parseSource(fileName, rootDir) {
if (fileName.includes('@dcloudio')) {
return fileName;
}
rootDir = (0, uni_cli_shared_1.normalizePath)(rootDir);
if (path_1.default.isAbsolute(fileName) && fileName.startsWith(rootDir)) {
return '@/' + (0, uni_cli_shared_1.normalizePath)(path_1.default.relative(rootDir, fileName));
}
return fileName;
}
exports.parseSource = parseSource;
function addEasyComponentAutoImports(easyComponentAutoImports, rootDir, tagName, fileName) {
if (easyComponentAutoImports[fileName]) {
return;
}
// 内置easycom,如 unicloud-db
if (fileName.includes('@dcloudio')) {
return;
}
rootDir = (0, uni_cli_shared_1.normalizePath)(rootDir);
if (path_1.default.isAbsolute(fileName) && fileName.startsWith(rootDir)) {
fileName = '@/' + (0, uni_cli_shared_1.normalizePath)(path_1.default.relative(rootDir, fileName));
}
// 加密插件easycom类型导入
if (fileName.includes('?uts-proxy')) {
const moduleId = path_1.default.basename(fileName.split('?uts-proxy')[0]);
fileName = `uts.sdk.modules.${(0, uni_cli_shared_1.camelize)(moduleId)}`;
}
const ident = (0, uni_cli_shared_1.genUTSComponentPublicInstanceIdent)(tagName);
easyComponentAutoImports[fileName] = [ident, ident];
}
exports.addEasyComponentAutoImports = addEasyComponentAutoImports;
@@ -0,0 +1,28 @@
import type * as _compiler from '@vue/compiler-sfc';
import type { CompilerError, SFCDescriptor } from '@vue/compiler-sfc';
export interface ResolvedOptions {
compiler: typeof _compiler;
root: string;
sourceMap: boolean;
targetLanguage?: 'kotlin';
classNamePrefix?: string;
genDefaultAs?: string;
}
export declare function getResolvedOptions(): ResolvedOptions;
export interface SFCParseResult {
descriptor: SFCDescriptor;
errors: Array<CompilerError | SyntaxError>;
}
export declare const cache: Map<string, _compiler.SFCDescriptor>;
declare module '@vue/compiler-sfc' {
interface SFCDescriptor {
id: string;
relativeFilename: string;
}
}
export declare function createDescriptor(filename: string, source: string, { root, sourceMap, compiler, }: ResolvedOptions & {
compiler: typeof _compiler;
}): SFCParseResult;
export declare function getDescriptor(filename: string, options: ResolvedOptions, createIfNotFound?: boolean): SFCDescriptor | undefined;
export declare function getSrcDescriptor(filename: string): SFCDescriptor;
export declare function setSrcDescriptor(filename: string, entry: SFCDescriptor): void;
@@ -0,0 +1,68 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setSrcDescriptor = exports.getSrcDescriptor = exports.getDescriptor = exports.createDescriptor = exports.cache = exports.getResolvedOptions = void 0;
const fs_1 = __importDefault(require("fs"));
const crypto_1 = require("crypto");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const utils_1 = require("../utils");
const script_1 = require("./sfc/script");
function getResolvedOptions() {
const options = {
root: process.env.UNI_INPUT_DIR,
sourceMap: (0, uni_cli_shared_1.enableSourceMap)(),
// eslint-disable-next-line no-restricted-globals
compiler: require('@vue/compiler-sfc'),
targetLanguage: process.env.UNI_UTS_TARGET_LANGUAGE,
genDefaultAs: script_1.scriptIdentifier,
};
if (process.env.UNI_COMPILE_TARGET === 'ext-api') {
options.classNamePrefix = 'Uni';
}
return options;
}
exports.getResolvedOptions = getResolvedOptions;
exports.cache = new Map();
function createDescriptor(filename, source, { root, sourceMap, compiler, }) {
// ensure the path is normalized in a way that is consistent inside
// project (relative to root) and on different systems.
const relativeFilename = (0, utils_1.parseUTSRelativeFilename)(filename, root);
// 传入normalizedPath是为了让sourcemap记录的是相对路径
const { descriptor, errors } = compiler.parse(source, {
filename: relativeFilename,
sourceMap,
});
descriptor.relativeFilename = relativeFilename;
// 重置为绝对路径
descriptor.filename = filename;
descriptor.id = getHash(relativeFilename);
exports.cache.set(filename, descriptor);
return { descriptor, errors };
}
exports.createDescriptor = createDescriptor;
function getDescriptor(filename, options, createIfNotFound = true) {
if (exports.cache.has(filename)) {
return exports.cache.get(filename);
}
if (createIfNotFound) {
const { descriptor, errors } = createDescriptor(filename, (0, uni_cli_shared_1.preUVueJs)((0, uni_cli_shared_1.preUVueHtml)(fs_1.default.readFileSync(filename, 'utf-8'))), options);
if (errors.length) {
throw errors[0];
}
return descriptor;
}
}
exports.getDescriptor = getDescriptor;
function getSrcDescriptor(filename) {
return exports.cache.get(filename);
}
exports.getSrcDescriptor = getSrcDescriptor;
function setSrcDescriptor(filename, entry) {
exports.cache.set(filename, entry);
}
exports.setSrcDescriptor = setSrcDescriptor;
function getHash(text) {
return (0, crypto_1.createHash)('sha256').update(text).digest('hex').substring(0, 8);
}
@@ -0,0 +1,2 @@
import type { Plugin } from 'vite';
export declare function uniAppUVuePlugin(): Plugin;
+117
View File
@@ -0,0 +1,117 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniAppUVuePlugin = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const shared_1 = require("@vue/shared");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const descriptorCache_1 = require("./descriptorCache");
const utils_1 = require("../utils");
const style_1 = require("./code/style");
const main_1 = require("./sfc/main");
function uniAppUVuePlugin() {
const options = (0, descriptorCache_1.getResolvedOptions)();
const appVue = (0, uni_cli_shared_1.resolveAppVue)(process.env.UNI_INPUT_DIR);
function isAppVue(id) {
return (0, uni_cli_shared_1.normalizePath)(id) === appVue;
}
return {
name: 'uni:app-uvue',
apply: 'build',
async resolveId(id) {
// serve sub-part requests (*?vue) as virtual modules
if ((0, uni_cli_shared_1.parseVueRequest)(id).query.vue) {
return id;
}
},
load(id) {
const { filename, query } = (0, uni_cli_shared_1.parseVueRequest)(id);
// select corresponding block for sub-part virtual modules
if (query.vue) {
if (query.src) {
return fs_extra_1.default.readFileSync(filename, 'utf-8');
}
const descriptor = (0, descriptorCache_1.getDescriptor)(filename, options);
let block;
if (query.type === 'style') {
block = descriptor.styles[query.index];
}
else if (query.index != null) {
block = descriptor.customBlocks[query.index];
}
if (block) {
return {
code: block.content,
map: block.map,
};
}
}
},
async transform(code, id) {
const { filename, query } = (0, uni_cli_shared_1.parseVueRequest)(id);
if (!(0, utils_1.isVue)(filename)) {
return;
}
if (!query.vue) {
// main request
return (0, main_1.transformMain)((0, utils_1.transformUniCloudMixinDataCom)(code), filename, {
...options,
componentType: isAppVue(filename)
? 'app'
: query.type === 'page'
? 'page'
: 'component',
}, this);
}
else {
// sub block request
const descriptor = query.src
? (0, descriptorCache_1.getSrcDescriptor)(filename)
: (0, descriptorCache_1.getDescriptor)(filename, options);
if (query.type === 'style') {
return (0, style_1.transformStyle)(code, descriptor, Number(query.index), options, this, filename);
}
}
},
generateBundle(_, bundle) {
// 遍历vue文件,填充style,尽量减少全局变量
Object.keys(bundle).forEach((name) => {
const file = bundle[name];
if (file &&
file.type === 'asset' &&
isVueFile(file.fileName) &&
(0, shared_1.isString)(file.source)) {
let fileName = (0, uni_cli_shared_1.normalizePath)(file.fileName);
if (process.env.UNI_APP_X_TSC === 'true') {
fileName = fileName.replace('.ts', '');
}
const className = process.env.UNI_COMPILE_TARGET === 'ext-api'
? // components/map/map.vue => UniMap
(0, uni_cli_shared_1.genUTSClassName)(path_1.default.basename(fileName), options.classNamePrefix)
: (0, uni_cli_shared_1.genUTSClassName)(fileName, options.classNamePrefix);
const classNameComment = `/*${className}Styles*/`;
if (file.source.includes(classNameComment)) {
const styleAssetName = fileName + '.style.uts';
const styleAsset = bundle[styleAssetName];
if (styleAsset &&
styleAsset.type === 'asset' &&
(0, shared_1.isString)(styleAsset.source)) {
file.source = file.source.replace(classNameComment, styleAsset.source.replace('export ', ''));
delete bundle[styleAssetName];
}
}
}
});
},
};
}
exports.uniAppUVuePlugin = uniAppUVuePlugin;
function isVueFile(filename) {
return (filename.endsWith('.uvue') ||
filename.endsWith('.vue') ||
filename.endsWith('.uvue.ts') ||
filename.endsWith('.vue.ts'));
}
@@ -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;

Some files were not shown because too many files have changed in this diff Show More