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
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+8
View File
@@ -0,0 +1,8 @@
/**
* 需要需要确保 vue 文件是处理过条件编译的
* @param platform
* @param vueFileName
* @returns
*/
export declare function transformExtApiVueFile(platform: 'app-android' | 'app-ios', // | 'app-harmony',
vueFileName: string): Promise<string | void | null>;
+69
View File
@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformExtApiVueFile = void 0;
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
const uni_nvue_styler_1 = require("@dcloudio/uni-nvue-styler");
const main_1 = require("./plugins/android/uvue/sfc/main");
/**
* 需要需要确保 vue 文件是处理过条件编译的
* @param platform
* @param vueFileName
* @returns
*/
async function transformExtApiVueFile(platform, // | 'app-harmony',
vueFileName) {
vueFileName = (0, uni_cli_shared_1.normalizePath)(vueFileName);
(0, uni_cli_shared_1.initPreContext)(platform === 'app-android' || platform === 'app-ios' ? 'app' : platform, process.env.UNI_CUSTOM_CONTEXT, platform, true);
const code = (0, fs_extra_1.readFileSync)(vueFileName, 'utf8');
if (platform === 'app-android') {
return transformAppAndroidExtApiComponent(vueFileName, code);
}
else if (platform === 'app-ios') {
return transformAppIosExtApiComponent(vueFileName, code);
}
}
exports.transformExtApiVueFile = transformExtApiVueFile;
async function transformAppAndroidExtApiComponent(vueFileName, code) {
const result = await (0, main_1.transformMain)(code, vueFileName, {
root: (0, path_1.dirname)(vueFileName),
targetLanguage: 'kotlin',
classNamePrefix: 'Uni',
genDefaultAs: '__sfc__',
sourceMap: false,
componentType: 'component',
});
if (!result) {
return null;
}
const { errors, uts, descriptor } = result;
if (errors.length > 0) {
throw new Error(errors.join('\n'));
}
const componentName = (0, path_1.basename)(vueFileName).split('.')[0];
const styleCode = await parseAppAndroidVueStyle(componentName, vueFileName, descriptor.styles.length > 0 ? descriptor.styles[0].content : '');
return uts.replace(`/*${(0, uni_cli_shared_1.genUTSClassName)(componentName, 'Uni')}Styles*/`, styleCode);
}
async function transformAppIosExtApiComponent(vueFileName, code) {
// TODO 编译vue为一个独立的js文件
}
async function parseAppAndroidVueStyle(name, vueFileName, cssCode) {
if (!cssCode) {
return `const ${(0, uni_cli_shared_1.genUTSClassName)(name, 'Uni')}Styles = []`;
}
const { code, messages } = await (0, uni_nvue_styler_1.parse)(cssCode, {
filename: vueFileName,
logLevel: 'ERROR',
map: true,
ts: true,
type: 'uvue',
platform: 'app-android',
});
if (messages.length) {
messages.forEach((m) => {
console.error(m);
});
}
return `const ${(0, uni_cli_shared_1.genUTSClassName)(name, 'Uni')}Styles = [${code}]`;
}
+6
View File
@@ -0,0 +1,6 @@
declare const _default: () => (import("vite").Plugin<any> | import("rollup").Plugin<any>[])[];
export default _default;
export { genUTSClassName as genClassName } from '@dcloudio/uni-cli-shared';
export { transformMain as transformVue } from './plugins/android/uvue/sfc/main';
export { transformExtApiVueFile } from './extApiComponents';
export { initUniAppIosCssPlugin } from './plugins/ios/plugin';
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initUniAppIosCssPlugin = exports.transformExtApiVueFile = exports.transformVue = exports.genClassName = void 0;
const plugins_1 = require("./plugins");
exports.default = () => {
return process.env.UNI_UTS_PLATFORM === 'app-android'
? (0, plugins_1.initAndroid)()
: (0, plugins_1.initIOS)();
};
var uni_cli_shared_1 = require("@dcloudio/uni-cli-shared");
Object.defineProperty(exports, "genClassName", { enumerable: true, get: function () { return uni_cli_shared_1.genUTSClassName; } });
var main_1 = require("./plugins/android/uvue/sfc/main");
Object.defineProperty(exports, "transformVue", { enumerable: true, get: function () { return main_1.transformMain; } });
var extApiComponents_1 = require("./extApiComponents");
Object.defineProperty(exports, "transformExtApiVueFile", { enumerable: true, get: function () { return extApiComponents_1.transformExtApiVueFile; } });
var plugin_1 = require("./plugins/ios/plugin");
Object.defineProperty(exports, "initUniAppIosCssPlugin", { enumerable: true, get: function () { return plugin_1.initUniAppIosCssPlugin; } });
+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;

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