提交 96e07ef9 编写于 作者: fxy060608's avatar fxy060608

wip(uts): compiler

上级 5d52d4f2
......@@ -17292,8 +17292,8 @@ function normalizeArg(arg) {
}
return arg;
}
function initUTSInstanceMethod(async, opts, instanceId) {
return initProxyFunction(async, opts, instanceId);
function initUTSInstanceMethod(async, opts, instanceId, proxy) {
return initProxyFunction(async, opts, instanceId, proxy);
}
function getProxy() {
if (!proxy) {
......@@ -17301,13 +17301,28 @@ function getProxy() {
}
return proxy;
}
function resolveSyncResult(res) {
function resolveSyncResult(res, returnOptions, instanceId, proxy) {
// devtools 环境是字符串?
if (isString(res)) {
res = JSON.parse(res);
}
if ((process.env.NODE_ENV !== 'production')) {
console.log('uts.invokeSync.result', res);
console.log('uts.invokeSync.result', res, returnOptions, instanceId, proxy);
}
if (res.errMsg) {
throw new Error(res.errMsg);
}
if (returnOptions) {
if (returnOptions.type === 'interface' && typeof res.params === 'number') {
if (res.params === instanceId && proxy) {
return proxy;
}
if (interfaceDefines[returnOptions.options]) {
const ProxyClass = initUTSProxyClass(extend({ instanceId: res.params }, interfaceDefines[returnOptions.options]));
return new ProxyClass();
}
}
}
return res.params;
}
function invokePropGetter(args) {
......@@ -17320,7 +17335,7 @@ function invokePropGetter(args) {
}
return resolveSyncResult(getProxy().invokeSync(args, () => { }));
}
function initProxyFunction(async, { moduleName, moduleType, package: pkg, class: cls, name: propOrMethod, method, companion, params: methodParams, errMsg, }, instanceId) {
function initProxyFunction(async, { moduleName, moduleType, package: pkg, class: cls, name: propOrMethod, method, companion, params: methodParams, return: returnOptions, errMsg, }, instanceId, proxy) {
const invokeCallback = ({ id, name, params, keepAlive, }) => {
const callback = callbacks[id];
if (callback) {
......@@ -17383,7 +17398,7 @@ function initProxyFunction(async, { moduleName, moduleType, package: pkg, class:
if ((process.env.NODE_ENV !== 'production')) {
console.log('uts.invokeSync.args', invokeArgs);
}
return resolveSyncResult(getProxy().invokeSync(invokeArgs, invokeCallback));
return resolveSyncResult(getProxy().invokeSync(invokeArgs, invokeCallback), returnOptions, instanceId, proxy);
};
}
function initUTSStaticMethod(async, opts) {
......@@ -17401,7 +17416,14 @@ function parseClassMethodName(name, methods) {
}
return name;
}
function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, constructor: { params: constructorParams }, methods, props, staticProps, staticMethods, errMsg, }) {
function isUndefined(value) {
return typeof value === 'undefined';
}
function isProxyInterfaceOptions(options) {
return !isUndefined(options.instanceId);
}
function initUTSProxyClass(options) {
const { moduleName, moduleType, package: pkg, class: cls, methods, props, errMsg, } = options;
const baseOptions = {
moduleName,
moduleType,
......@@ -17409,6 +17431,18 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
class: cls,
errMsg,
};
let instanceId;
let constructorParams = [];
let staticMethods = {};
let staticProps = [];
if (isProxyInterfaceOptions(options)) {
instanceId = options.instanceId;
}
else {
constructorParams = options.constructor.params;
staticMethods = options.staticMethods;
staticProps = options.staticProps;
}
// iOS 需要为 ByJs 的 class 构造函数(如果包含JSONObject或UTSCallback类型)补充最后一个参数
if (typeof plus !== 'undefined' && plus.os.name === 'iOS') {
if (constructorParams.find((p) => p.type === 'UTSCallback' || p.type.indexOf('JSONObject') > 0)) {
......@@ -17422,11 +17456,14 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
}
const target = {};
// 初始化实例 ID
const instanceId = initProxyFunction(false, extend({ name: 'constructor', params: constructorParams }, baseOptions), 0).apply(null, params);
if (isUndefined(instanceId)) {
// 未指定instanceId
instanceId = initProxyFunction(false, extend({ name: 'constructor', params: constructorParams }, baseOptions), 0).apply(null, params);
}
if (!instanceId) {
throw new Error(`new ${cls} is failed`);
}
return new Proxy(this, {
const proxy = new Proxy(this, {
get(_, name) {
if (!target[name]) {
//实例方法
......@@ -17436,7 +17473,7 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
target[name] = initUTSInstanceMethod(!!async, extend({
name,
params,
}, baseOptions), instanceId);
}, baseOptions), instanceId, proxy);
}
else if (props.includes(name)) {
// 实例属性
......@@ -17452,6 +17489,7 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
return target[name];
},
});
return proxy;
}
};
const staticMethodCache = {};
......@@ -17501,6 +17539,10 @@ function initUTSClassName(moduleName, className, is_uni_modules) {
}
return '';
}
const interfaceDefines = {};
function registerUTSInterface(name, define) {
interfaceDefines[name] = define;
}
const pluginDefines = {};
function registerUTSPlugin(name, define) {
pluginDefines[name] = define;
......@@ -19783,6 +19825,7 @@ var uni$1 = {
readBLECharacteristicValue: readBLECharacteristicValue,
redirectTo: redirectTo,
registerRuntime: registerRuntime,
registerUTSInterface: registerUTSInterface,
registerUTSPlugin: registerUTSPlugin,
removeInterceptor: removeInterceptor,
removeSavedFile: removeSavedFile,
......
......@@ -92,6 +92,7 @@ export {
initUTSPackageName,
requireUTSPlugin,
registerUTSPlugin,
registerUTSInterface,
} from './plugin/uts'
export * from './ad/rewardedVideoAd'
......
import { isPlainObject, hasOwn, extend, capitalize } from 'uni-shared';
import { isPlainObject, hasOwn, extend, capitalize, isString } from 'uni-shared';
let callbackId = 1;
let proxy;
......@@ -18,8 +18,8 @@ function normalizeArg(arg) {
}
return arg;
}
function initUTSInstanceMethod(async, opts, instanceId) {
return initProxyFunction(async, opts, instanceId);
function initUTSInstanceMethod(async, opts, instanceId, proxy) {
return initProxyFunction(async, opts, instanceId, proxy);
}
function getProxy() {
if (!proxy) {
......@@ -27,13 +27,28 @@ function getProxy() {
}
return proxy;
}
function resolveSyncResult(res) {
function resolveSyncResult(res, returnOptions, instanceId, proxy) {
// devtools 环境是字符串?
if (isString(res)) {
res = JSON.parse(res);
}
if ((process.env.NODE_ENV !== 'production')) {
console.log('uts.invokeSync.result', res);
console.log('uts.invokeSync.result', res, returnOptions, instanceId, proxy);
}
if (res.errMsg) {
throw new Error(res.errMsg);
}
if (returnOptions) {
if (returnOptions.type === 'interface' && typeof res.params === 'number') {
if (res.params === instanceId && proxy) {
return proxy;
}
if (interfaceDefines[returnOptions.options]) {
const ProxyClass = initUTSProxyClass(extend({ instanceId: res.params }, interfaceDefines[returnOptions.options]));
return new ProxyClass();
}
}
}
return res.params;
}
function invokePropGetter(args) {
......@@ -46,7 +61,7 @@ function invokePropGetter(args) {
}
return resolveSyncResult(getProxy().invokeSync(args, () => { }));
}
function initProxyFunction(async, { moduleName, moduleType, package: pkg, class: cls, name: propOrMethod, method, companion, params: methodParams, errMsg, }, instanceId) {
function initProxyFunction(async, { moduleName, moduleType, package: pkg, class: cls, name: propOrMethod, method, companion, params: methodParams, return: returnOptions, errMsg, }, instanceId, proxy) {
const invokeCallback = ({ id, name, params, keepAlive, }) => {
const callback = callbacks[id];
if (callback) {
......@@ -109,7 +124,7 @@ function initProxyFunction(async, { moduleName, moduleType, package: pkg, class:
if ((process.env.NODE_ENV !== 'production')) {
console.log('uts.invokeSync.args', invokeArgs);
}
return resolveSyncResult(getProxy().invokeSync(invokeArgs, invokeCallback));
return resolveSyncResult(getProxy().invokeSync(invokeArgs, invokeCallback), returnOptions, instanceId, proxy);
};
}
function initUTSStaticMethod(async, opts) {
......@@ -127,7 +142,14 @@ function parseClassMethodName(name, methods) {
}
return name;
}
function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, constructor: { params: constructorParams }, methods, props, staticProps, staticMethods, errMsg, }) {
function isUndefined(value) {
return typeof value === 'undefined';
}
function isProxyInterfaceOptions(options) {
return !isUndefined(options.instanceId);
}
function initUTSProxyClass(options) {
const { moduleName, moduleType, package: pkg, class: cls, methods, props, errMsg, } = options;
const baseOptions = {
moduleName,
moduleType,
......@@ -135,6 +157,18 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
class: cls,
errMsg,
};
let instanceId;
let constructorParams = [];
let staticMethods = {};
let staticProps = [];
if (isProxyInterfaceOptions(options)) {
instanceId = options.instanceId;
}
else {
constructorParams = options.constructor.params;
staticMethods = options.staticMethods;
staticProps = options.staticProps;
}
// iOS 需要为 ByJs 的 class 构造函数(如果包含JSONObject或UTSCallback类型)补充最后一个参数
if (typeof plus !== 'undefined' && plus.os.name === 'iOS') {
if (constructorParams.find((p) => p.type === 'UTSCallback' || p.type.indexOf('JSONObject') > 0)) {
......@@ -148,11 +182,14 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
}
const target = {};
// 初始化实例 ID
const instanceId = initProxyFunction(false, extend({ name: 'constructor', params: constructorParams }, baseOptions), 0).apply(null, params);
if (isUndefined(instanceId)) {
// 未指定instanceId
instanceId = initProxyFunction(false, extend({ name: 'constructor', params: constructorParams }, baseOptions), 0).apply(null, params);
}
if (!instanceId) {
throw new Error(`new ${cls} is failed`);
}
return new Proxy(this, {
const proxy = new Proxy(this, {
get(_, name) {
if (!target[name]) {
//实例方法
......@@ -162,7 +199,7 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
target[name] = initUTSInstanceMethod(!!async, extend({
name,
params,
}, baseOptions), instanceId);
}, baseOptions), instanceId, proxy);
}
else if (props.includes(name)) {
// 实例属性
......@@ -178,6 +215,7 @@ function initUTSProxyClass({ moduleName, moduleType, package: pkg, class: cls, c
return target[name];
},
});
return proxy;
}
};
const staticMethodCache = {};
......@@ -227,6 +265,10 @@ function initUTSClassName(moduleName, className, is_uni_modules) {
}
return '';
}
const interfaceDefines = {};
function registerUTSInterface(name, define) {
interfaceDefines[name] = define;
}
const pluginDefines = {};
function registerUTSPlugin(name, define) {
pluginDefines[name] = define;
......@@ -239,4 +281,4 @@ function requireUTSPlugin(name) {
return define;
}
export { initUTSClassName, initUTSIndexClassName, initUTSPackageName, initUTSProxyClass, initUTSProxyFunction, normalizeArg, registerUTSPlugin, requireUTSPlugin };
export { initUTSClassName, initUTSIndexClassName, initUTSPackageName, initUTSProxyClass, initUTSProxyFunction, normalizeArg, registerUTSInterface, registerUTSPlugin, requireUTSPlugin };
import { isPlainObject, hasOwn, extend, capitalize } from '@vue/shared'
import {
isPlainObject,
hasOwn,
extend,
capitalize,
isString,
} from '@vue/shared'
declare const uni: any
declare const plus: any
let callbackId = 1
......@@ -23,9 +29,10 @@ export function normalizeArg(arg: unknown) {
function initUTSInstanceMethod(
async: boolean,
opts: ProxyFunctionOptions,
instanceId: number
instanceId: number,
proxy: unknown
) {
return initProxyFunction(async, opts, instanceId)
return initProxyFunction(async, opts, instanceId, proxy)
}
interface Parameter {
......@@ -38,6 +45,10 @@ interface ModuleOptions {
moduleType: 'built-in' | ''
}
interface ProxyFunctionReturnOptions {
type: 'interface'
options: string
}
interface ProxyFunctionOptions extends ModuleOptions {
/**
* 是否是入口类
......@@ -67,6 +78,27 @@ interface ProxyFunctionOptions extends ModuleOptions {
* 方法参数列表
*/
params: Parameter[]
/**
* 返回值类型
*/
return?: ProxyFunctionReturnOptions
/**
* 运行时提示的错误信息
*/
errMsg?: string
}
interface ProxyInterfaceOptions extends ModuleOptions {
instanceId: number
package: string
class: string
props: string[]
methods: {
[name: string]: {
async?: boolean
params: Parameter[]
}
}
/**
* 运行时提示的错误信息
*/
......@@ -175,13 +207,38 @@ function getProxy(): {
return proxy
}
function resolveSyncResult(res: InvokeSyncRes) {
function resolveSyncResult(
res: InvokeSyncRes,
returnOptions?: ProxyFunctionReturnOptions,
instanceId?: number,
proxy?: unknown
) {
// devtools 环境是字符串?
if (isString(res)) {
res = JSON.parse(res)
}
if (__DEV__) {
console.log('uts.invokeSync.result', res)
console.log('uts.invokeSync.result', res, returnOptions, instanceId, proxy)
}
if (res.errMsg) {
throw new Error(res.errMsg)
}
if (returnOptions) {
if (returnOptions.type === 'interface' && typeof res.params === 'number') {
if (res.params === instanceId && proxy) {
return proxy
}
if (interfaceDefines[returnOptions.options]) {
const ProxyClass = initUTSProxyClass(
extend(
{ instanceId: res.params },
interfaceDefines[returnOptions.options]
)
)
return new ProxyClass()
}
}
}
return res.params
}
......@@ -207,9 +264,11 @@ function initProxyFunction(
method,
companion,
params: methodParams,
return: returnOptions,
errMsg,
}: ProxyFunctionOptions,
instanceId: number
instanceId: number,
proxy?: unknown
) {
const invokeCallback = ({
id,
......@@ -275,7 +334,12 @@ function initProxyFunction(
if (__DEV__) {
console.log('uts.invokeSync.args', invokeArgs)
}
return resolveSyncResult(getProxy().invokeSync(invokeArgs, invokeCallback))
return resolveSyncResult(
getProxy().invokeSync(invokeArgs, invokeCallback),
returnOptions,
instanceId,
proxy
)
}
}
......@@ -297,18 +361,29 @@ function parseClassMethodName(name: string, methods: Record<string, unknown>) {
return name
}
export function initUTSProxyClass({
moduleName,
moduleType,
package: pkg,
class: cls,
constructor: { params: constructorParams },
methods,
props,
staticProps,
staticMethods,
errMsg,
}: ProxyClassOptions): any {
function isUndefined(value: unknown): boolean {
return typeof value === 'undefined'
}
function isProxyInterfaceOptions(
options: unknown
): options is ProxyInterfaceOptions {
return !isUndefined((options as any).instanceId)
}
export function initUTSProxyClass(
options: ProxyClassOptions | ProxyInterfaceOptions
): any {
const {
moduleName,
moduleType,
package: pkg,
class: cls,
methods,
props,
errMsg,
} = options
const baseOptions = {
moduleName,
moduleType,
......@@ -316,6 +391,20 @@ export function initUTSProxyClass({
class: cls,
errMsg,
}
let instanceId: number | undefined
let constructorParams: Parameter[] = []
let staticMethods: ProxyClassOptions['staticMethods'] = {}
let staticProps: ProxyClassOptions['staticProps'] = []
if (isProxyInterfaceOptions(options)) {
instanceId = options.instanceId
} else {
constructorParams = options.constructor.params
staticMethods = options.staticMethods
staticProps = options.staticProps
}
// iOS 需要为 ByJs 的 class 构造函数(如果包含JSONObject或UTSCallback类型)补充最后一个参数
if (typeof plus !== 'undefined' && plus.os.name === 'iOS') {
if (
......@@ -333,15 +422,21 @@ export function initUTSProxyClass({
}
const target: Record<string, Function> = {}
// 初始化实例 ID
const instanceId = initProxyFunction(
false,
extend({ name: 'constructor', params: constructorParams }, baseOptions),
0
).apply(null, params) as number
if (isUndefined(instanceId)) {
// 未指定instanceId
instanceId = initProxyFunction(
false,
extend(
{ name: 'constructor', params: constructorParams },
baseOptions
),
0
).apply(null, params) as number
}
if (!instanceId) {
throw new Error(`new ${cls} is failed`)
}
return new Proxy(this, {
const proxy = new Proxy(this, {
get(_, name) {
if (!target[name as string]) {
//实例方法
......@@ -357,14 +452,15 @@ export function initUTSProxyClass({
},
baseOptions
),
instanceId
instanceId!,
proxy
)
} else if (props.includes(name as string)) {
// 实例属性
return invokePropGetter({
moduleName,
moduleType,
id: instanceId,
id: instanceId!,
name: name as string,
errMsg,
})
......@@ -373,6 +469,7 @@ export function initUTSProxyClass({
return target[name as string]
},
})
return proxy
}
}
const staticMethodCache: Record<string, Function> = {}
......@@ -444,6 +541,11 @@ export function initUTSClassName(
return ''
}
const interfaceDefines: Record<string, ProxyClassOptions> = {}
export function registerUTSInterface(name: string, define: ProxyClassOptions) {
interfaceDefines[name] = define
}
const pluginDefines: Record<string, Record<string, unknown>> = {}
export function registerUTSPlugin(
name: string,
......
......@@ -2,7 +2,7 @@
exports[`code genProxyCode 1`] = `
"
const { initUTSProxyClass, initUTSProxyFunction, initUTSPackageName, initUTSIndexClassName, initUTSClassName } = uni
const { registerUTSInterface, initUTSProxyClass, initUTSProxyFunction, initUTSPackageName, initUTSIndexClassName, initUTSClassName } = uni
const name = 'test-uts'
const moduleName = '测试'
const moduleType = 'built-in'
......@@ -13,18 +13,20 @@ const cls = /*#__PURE__*/ initUTSIndexClassName(name, is_uni_modules)
export const TestUTSComponent = {}
export const onMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'onMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback"}]})
export const offMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'offMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback","default":"UTSNull"}]})
registerUTSInterface('RequestTaskOptions',Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, 'RequestTaskByJsProxy', is_uni_modules) }, {"methods":{"startByJs":{"async":false,"params":[],"return":{}},"abortByJs":{"async":false,"params":[],"return":{"type":"interface","options":"RequestTaskOptions"}}},"props":[]} ))
export const onMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'onMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback"}], return: ""})
export const offMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'offMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback","default":"UTSNull"}], return: ""})
export default /*#__PURE__*/ initUTSProxyClass(Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, 'UserByJs', is_uni_modules) }, {"constructor":{"params":[]},"methods":{},"staticMethods":{},"props":[],"staticProps":[]} ))
export const a = 1
export const showToast1 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast1ByJs', params: [{"name":"msg","type":"string"}]})
export const showToast2 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast2ByJs', params: [{"name":"msg","type":"string"}]})
export const showToast1 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast1ByJs', params: [{"name":"msg","type":"string"}], return: ""})
export const showToast2 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast2ByJs', params: [{"name":"msg","type":"string"}], return: ""})
export const request = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'requestByJs', params: [], return: {"type":"interface","options":"RequestTaskOptions"}})
"
`;
exports[`code genProxyCode cjs 1`] = `
"
const { initUTSProxyClass, initUTSProxyFunction, initUTSPackageName, initUTSIndexClassName, initUTSClassName } = uni
const { registerUTSInterface, initUTSProxyClass, initUTSProxyFunction, initUTSPackageName, initUTSIndexClassName, initUTSClassName } = uni
const name = 'test-uts'
const moduleName = ''
const moduleType = ''
......@@ -37,13 +39,15 @@ const exports = { __esModule: true }
exports.TestUTSComponent = {}
exports.onMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'onMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback"}]})
exports.offMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'offMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback","default":"UTSNull"}]})
registerUTSInterface('RequestTaskOptions',Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, 'RequestTaskByJsProxy', is_uni_modules) }, {"methods":{"startByJs":{"async":false,"params":[],"return":{}},"abortByJs":{"async":false,"params":[],"return":{"type":"interface","options":"RequestTaskOptions"}}},"props":[]} ))
exports.onMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'onMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback"}], return: ""})
exports.offMemoryWarning = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'offMemoryWarningByJs', params: [{"name":"callback","type":"UTSCallback","default":"UTSNull"}], return: ""})
exports.default = initUTSProxyClass(Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, 'UserByJs', is_uni_modules) }, {"constructor":{"params":[]},"methods":{},"staticMethods":{},"props":[],"staticProps":[]} ))
const a = 1
exports.a = a
exports.showToast1 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast1ByJs', params: [{"name":"msg","type":"string"}]})
exports.showToast2 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast2ByJs', params: [{"name":"msg","type":"string"}]})
exports.showToast1 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast1ByJs', params: [{"name":"msg","type":"string"}], return: ""})
exports.showToast2 = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'showToast2ByJs', params: [{"name":"msg","type":"string"}], return: ""})
exports.request = /*#__PURE__*/ initUTSProxyFunction(false, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: 'requestByJs', params: [], return: {"type":"interface","options":"RequestTaskOptions"}})
uni.registerUTSPlugin('utssdk/test-uts', exports)
"
`;
......@@ -11,10 +11,10 @@
"md5": "d41d8cd98f00b204e9800998ecf8427e"
},
"index.uts": {
"md5": "003a8c59606c6e6f1871cba778b32f60"
"md5": "fb7530a446dae78d4853ff5bf698ed20"
},
"interface.uts": {
"md5": "6dc8bfe1c672fd466b86d38c5e8e6212"
"md5": "8a55e93e1d27e88f34d38b8a7c0a3608"
},
"package.json": {
"md5": "9595031a0d4158abb72060cdf3a200c1"
......
......@@ -11,10 +11,10 @@
"md5": "d41d8cd98f00b204e9800998ecf8427e"
},
"index.uts": {
"md5": "003a8c59606c6e6f1871cba778b32f60"
"md5": "fb7530a446dae78d4853ff5bf698ed20"
},
"interface.uts": {
"md5": "6dc8bfe1c672fd466b86d38c5e8e6212"
"md5": "8a55e93e1d27e88f34d38b8a7c0a3608"
},
"package.json": {
"md5": "9595031a0d4158abb72060cdf3a200c1"
......
import { ShowToast } from "./interface.uts"
import { ShowToast, RequestTask } from "./interface.uts"
export function onMemoryWarning(callback: (level: number) => void) { }
export function offMemoryWarning(
......@@ -14,4 +14,6 @@ export const showToast1: ShowToast = (msg) => {
}
export const showToast2: ShowToast = function showToast(msg) {
console.log(msg)
}
\ No newline at end of file
}
export function request(): RequestTask { }
\ No newline at end of file
export type ShowToast = (msg: string) => void
\ No newline at end of file
export type ShowToast = (msg: string) => void
export interface RequestTask {
start(): void
abort(): RequestTask
}
\ No newline at end of file
import fs from 'fs'
import path from 'path'
import { camelize, capitalize, hasOwn, isArray } from '@vue/shared'
import {
camelize,
capitalize,
hasOwn,
isArray,
isPlainObject,
isString,
} from '@vue/shared'
import type {
ArrowFunctionExpression,
......@@ -16,6 +23,7 @@ import type {
Param,
Span,
TsFnParameter,
TsInterfaceDeclaration,
TsType,
TsTypeAliasDeclaration,
TsTypeAnnotation,
......@@ -36,7 +44,12 @@ export const enum FORMATS {
CJS = 'cjs',
}
type Types = { class: string[]; fn: Record<string, Param[]> }
// 不应该用 class,应该用lit,调整起来影响较多,暂不调整
type Types = {
interface: Record<string, { returned: boolean; decl: TsInterfaceDeclaration }>
class: string[]
fn: Record<string, Param[]>
}
interface Meta {
exports: Record<string, 'var' | 'function' | 'class'>
......@@ -70,8 +83,9 @@ export async function genProxyCode(
}
options.types = await parseInterfaceTypes(module, options)
options.meta!.types = parseMetaTypes(options.types)
const decls = await parseModuleDecls(module, options)
return `
const { initUTSProxyClass, initUTSProxyFunction, initUTSPackageName, initUTSIndexClassName, initUTSClassName } = uni
const { registerUTSInterface, initUTSProxyClass, initUTSProxyFunction, initUTSPackageName, initUTSIndexClassName, initUTSClassName } = uni
const name = '${name}'
const moduleName = '${moduleName || ''}'
const moduleType = '${moduleType || ''}'
......@@ -92,12 +106,7 @@ ${genComponentsCode(
options.iosComponents || {}
)}
${genModuleCode(
await parseModuleDecls(module, options),
format,
options.pluginRelativeDir!,
options.meta!
)}
${genModuleCode(decls, format, options.pluginRelativeDir!, options.meta!)}
`
}
......@@ -186,6 +195,25 @@ function exportVarCode(format: FORMATS, kind: VariableDeclarationKind) {
return `exports.`
}
function isClassReturnOptions(value: unknown): value is { options: string } {
return (
isPlainObject(value) &&
(value as any).type === 'interface' &&
isString((value as any).options)
)
}
function genClassOptionsCode(
options: ProxyClass['options'] | ProxyInterface['options']
): string {
return JSON.stringify(options, (key, value) => {
if (key === 'return' && isClassReturnOptions(value)) {
return { type: 'interface', options: `${value.options}Options` }
}
return value
})
}
function genModuleCode(
decls: ProxyDecl[],
format: FORMATS = FORMATS.ES,
......@@ -196,14 +224,22 @@ function genModuleCode(
const exportDefault = exportDefaultCode(format)
const exportConst = exportVarCode(format, 'const')
decls.forEach((decl) => {
if (decl.type === 'Class') {
if (decl.type === 'InterfaceDeclaration') {
codes.push(
`registerUTSInterface('${
decl.cls
}Options',Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, '${
decl.cls
}ByJsProxy', is_uni_modules) }, ${genClassOptionsCode(decl.options)} ))`
)
} else if (decl.type === 'Class') {
meta.exports[decl.cls] = decl.isVar ? 'var' : 'class'
if (decl.isDefault) {
codes.push(
`${exportDefault}initUTSProxyClass(Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, '${
decl.cls
}ByJs', is_uni_modules) }, ${JSON.stringify(decl.options)} ))`
}ByJs', is_uni_modules) }, ${genClassOptionsCode(decl.options)} ))`
)
} else {
codes.push(
......@@ -211,19 +247,23 @@ function genModuleCode(
decl.cls
} = /*#__PURE__*/ initUTSProxyClass(Object.assign({ moduleName, moduleType, errMsg, package: pkg, class: initUTSClassName(name, '${
decl.cls
}ByJs', is_uni_modules) }, ${JSON.stringify(decl.options)} ))`
}ByJs', is_uni_modules) }, ${genClassOptionsCode(decl.options)} ))`
)
}
} else if (decl.type === 'FunctionDeclaration') {
meta.exports[decl.method] = decl.isVar ? 'var' : 'function'
const returnOptions = decl.return
? { type: decl.return.type, options: decl.return.options + 'Options' }
: ''
if (decl.isDefault) {
codes.push(
`${exportDefault}initUTSProxyFunction(${
decl.async
}, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: '${
decl.method
}ByJs', params: ${JSON.stringify(decl.params)}})`
}ByJs', params: ${JSON.stringify(
decl.params
)}, return: ${JSON.stringify(returnOptions)}})`
)
} else {
codes.push(
......@@ -231,7 +271,9 @@ function genModuleCode(
decl.async
}, { moduleName, moduleType, errMsg, main: true, package: pkg, class: cls, name: '${
decl.method
}ByJs', params: ${JSON.stringify(decl.params)}})`
}ByJs', params: ${JSON.stringify(
decl.params
)}, return: ${JSON.stringify(returnOptions)}})`
)
}
} else if (decl.type === 'VariableDeclaration') {
......@@ -272,7 +314,7 @@ function genModuleCode(
}
/**
* 解析接口文件中定义的类型信息(主要是解析函数类型参数类型列表)
* 解析接口文件中定义的类型信息
* @param module
* @param options
* @returns
......@@ -284,6 +326,7 @@ async function parseInterfaceTypes(
const interfaceFilename = resolveRootInterface(module, options)
if (!interfaceFilename) {
return {
interface: {},
class: [],
fn: {},
}
......@@ -300,8 +343,9 @@ async function parseInterfaceTypes(
} catch (e) {
console.error(parseUTSSyntaxError(e, options.inputDir!))
}
const classTypes: string[] = []
const fnTypes: Record<string, Param[]> = {}
const interfaceTypes: Types['interface'] = {}
const classTypes: Types['class'] = []
const fnTypes: Types['fn'] = {}
const exportNamed: string[] = []
if (ast) {
......@@ -322,19 +366,29 @@ async function parseInterfaceTypes(
})
ast.body.filter((node) => {
if (
node.type === 'ExportDeclaration' &&
node.declaration.type === 'TsTypeAliasDeclaration'
) {
parseTypes(node.declaration, classTypes, fnTypes)
if (node.type === 'ExportDeclaration') {
if (node.declaration.type === 'TsTypeAliasDeclaration') {
parseTypes(node.declaration, classTypes, fnTypes)
} else if (node.declaration.type === 'TsInterfaceDeclaration') {
interfaceTypes[node.declaration.id.value] = {
returned: false,
decl: node.declaration,
}
}
} else if (node.type === 'TsTypeAliasDeclaration') {
if (exportNamed.includes(node.id.value)) {
parseTypes(node, classTypes, fnTypes)
}
} else if (node.type === 'TsInterfaceDeclaration') {
interfaceTypes[node.id.value] = {
returned: false,
decl: node,
}
}
})
}
return {
interface: interfaceTypes,
class: classTypes,
fn: fnTypes,
}
......@@ -396,7 +450,16 @@ async function parseModuleDecls(module: string, options: GenProxyCodeOptions) {
function mergeDecls(from: ProxyDecl[], to: ProxyDecl[]) {
from.forEach((item) => {
if (item.type === 'Class') {
if (item.type === 'InterfaceDeclaration') {
if (
!to.find(
(toItem) =>
toItem.type === 'InterfaceDeclaration' && toItem.cls === item.cls
)
) {
to.push(item)
}
} else if (item.type === 'Class') {
if (
!to.find(
(toItem) =>
......@@ -488,7 +551,20 @@ async function parseCode(
return []
}
type ProxyDecl = ProxyFunctionDeclaration | ProxyClass | VariableDeclaration
type ProxyDecl =
| ProxyInterface
| ProxyFunctionDeclaration
| ProxyClass
| VariableDeclaration
interface ProxyInterface {
type: 'InterfaceDeclaration'
cls: string
options: {
methods: Record<string, any>
props: string[]
}
}
interface ProxyFunctionDeclaration {
type: 'FunctionDeclaration'
......@@ -497,6 +573,10 @@ interface ProxyFunctionDeclaration {
params: Parameter[]
isDefault: boolean
isVar: boolean
return?: {
type: 'interface'
options: string
}
}
interface ProxyClass {
......@@ -563,7 +643,16 @@ function parseAst(
}
}
})
return decls
const interfaces: ProxyInterface[] = []
Object.keys(types.interface).forEach((name) => {
const options = types.interface[name]
if (options.returned) {
interfaces.push(
genInterfaceDeclaration(types, options.decl, resolveTypeReferenceName)
)
}
})
return [...interfaces, ...decls]
}
function isReturnPromise(anno?: TsTypeAnnotation) {
......@@ -582,6 +671,7 @@ function genProxyFunction(
method: string,
async: boolean,
params: Parameter[],
ret: string = '',
isDefault: boolean = false,
isVar: boolean = false
): ProxyFunctionDeclaration {
......@@ -590,6 +680,7 @@ function genProxyFunction(
method,
async,
params,
return: ret ? { type: 'interface', options: ret } : undefined,
isDefault,
isVar,
}
......@@ -719,6 +810,30 @@ function resolveFunctionParams(
return result
}
function parseReturnInterface(types: Types, returnType: TsType): string {
switch (returnType.type) {
case 'TsTypeReference':
if (returnType.typeName.type === 'Identifier') {
if (hasOwn(types.interface, returnType.typeName.value)) {
types.interface[returnType.typeName.value].returned = true
return returnType.typeName.value
}
}
break
case 'TsUnionType':
for (const type of returnType.types) {
if (type.type === 'TsKeywordType') {
continue
}
return parseReturnInterface(types, type)
}
break
case 'TsParenthesizedType':
return parseReturnInterface(types, returnType.typeAnnotation)
}
return ''
}
function genFunctionDeclaration(
types: Types,
decl: FunctionDeclaration | FunctionExpression,
......@@ -730,11 +845,81 @@ function genFunctionDeclaration(
decl.identifier!.value,
decl.async || isReturnPromise(decl.returnType),
resolveFunctionParams(types, decl.params, resolveTypeReferenceName),
decl.returnType
? parseReturnInterface(types, decl.returnType.typeAnnotation)
: '',
isDefault,
isVar
)
}
function genInterfaceDeclaration(
types: Types,
decl: TsInterfaceDeclaration,
resolveTypeReferenceName: ResolveTypeReferenceName
): ProxyInterface {
const cls = decl.id.value
const methods: ProxyClass['options']['methods'] = {}
const props: string[] = []
decl.body.body.forEach((item) => {
if (item.type === 'TsMethodSignature') {
if (item.key.type === 'Identifier') {
let returnOptions = {}
if (item.typeAnn) {
let returnInterface = parseReturnInterface(
types,
item.typeAnn.typeAnnotation
)
if (returnInterface) {
returnOptions = {
type: 'interface',
options: returnInterface,
}
}
}
const name = item.key.value
const value = {
async: isReturnPromise(item.typeAnn),
params: resolveFunctionParams(
types,
tsParamsToParams(item.params),
resolveTypeReferenceName
),
return: returnOptions,
}
methods[name + 'ByJs'] = value
}
} else if (item.type === 'TsPropertySignature') {
if (item.key.type === 'Identifier') {
props.push(item.key.value)
}
}
})
return {
type: 'InterfaceDeclaration',
cls,
options: {
methods,
props,
},
}
}
function tsParamsToParams(tsParams: TsFnParameter[]) {
const params: Param[] = []
tsParams.forEach((p) => {
if (p.type === 'Identifier') {
params.push({
type: 'Parameter',
pat: createIdentifier(p.value),
span: {} as Span,
})
}
})
return params
}
function genClassDeclaration(
types: Types,
decl: ClassDeclaration | ClassExpression,
......@@ -743,11 +928,8 @@ function genClassDeclaration(
): ProxyClass {
const cls = decl.identifier!.value
const constructor: { params: Parameter[] } = { params: [] }
const methods: Record<string, { async?: boolean; params: Parameter[] }> = {}
const staticMethods: Record<
string,
{ async?: boolean; params: Parameter[] }
> = {}
const methods: ProxyClass['options']['methods'] = {}
const staticMethods: ProxyClass['options']['staticMethods'] = {}
const props: string[] = []
const staticProps: string[] = []
decl.body.forEach((item) => {
......@@ -759,6 +941,20 @@ function genClassDeclaration(
)
} else if (item.type === 'ClassMethod') {
if (item.key.type === 'Identifier') {
let returnOptions = {}
if (item.function.returnType) {
let returnInterface = parseReturnInterface(
types,
item.function.returnType.typeAnnotation
)
if (returnInterface) {
returnOptions = {
type: 'interface',
options: returnInterface,
}
}
}
const name = item.key.value
const value = {
async:
......@@ -768,6 +964,7 @@ function genClassDeclaration(
item.function.params,
resolveTypeReferenceName
),
returnOptions,
}
if (item.isStatic) {
staticMethods[name + 'ByJs'] = value
......@@ -879,6 +1076,7 @@ function createFunctionDeclaration(
if (func.type === 'FunctionExpression') {
params = func.params
} else if (func.type === 'ArrowFunctionExpression') {
params = []
func.params.forEach((p) => {
if (p.type === 'Identifier') {
params!.push({
......
......@@ -134,6 +134,9 @@ export function generateCodeFrame(
}
export function parseUTSSyntaxError(error: any, inputDir: string): string {
if (error instanceof Error) {
error = error.message + (error.stack ? `\n` + error.stack : ``)
}
let msg = String(error).replace(/\t/g, ' ')
let res: RegExpExecArray | null = null
const syntaxErrorRe = /(,-\[(.*):(\d+):(\d+)\])/g
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册