mirror of
https://github.com/tidys/cc-inspector-chrome
synced 2025-04-19 16:38:41 +00:00
finish object show
This commit is contained in:
parent
57a3b8a39c
commit
87a5a0dd16
@ -13,6 +13,7 @@
|
||||
"@types/node": "^14.14.37",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"core-js": "^3.6.5",
|
||||
"uuid": "^8.3.2",
|
||||
"element-ui": "^2.15.1",
|
||||
"fs-extra": "^9.1.0",
|
||||
"less": "^4.1.1",
|
||||
@ -22,6 +23,7 @@
|
||||
"vue-property-decorator": "^9.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/uuid": "^8.3.1",
|
||||
"@types/chrome": "0.0.133",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
|
@ -107,12 +107,12 @@ class PortManagement {
|
||||
if (id && id > -1) {
|
||||
let portMan = this.find(id);
|
||||
if (portMan) {
|
||||
let data = new PluginEvent(
|
||||
Page.Background,
|
||||
Page.Content,
|
||||
Msg.Test,
|
||||
{url: tab.url}
|
||||
);
|
||||
// let data = new PluginEvent(
|
||||
// Page.Background,
|
||||
// Page.Content,
|
||||
// Msg.Test,
|
||||
// {url: tab.url}
|
||||
// );
|
||||
// portMan.sendContentMsg(data);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export enum Page {
|
||||
Inject = "Inject",
|
||||
Devtools = "Devtools",
|
||||
Background = 'Background',
|
||||
Background = "Background",
|
||||
Content = "Content",
|
||||
Popup = "Popup",
|
||||
Options = "Options",
|
||||
@ -14,9 +14,9 @@ export enum Msg {
|
||||
MemoryInfo = "memory-info",//
|
||||
TabsInfo = "tabs_info", // 当前页面信息
|
||||
GetTabID = "GetTabID", // 获取页面ID
|
||||
Test='Test',
|
||||
GetObjectItemData = "GetObjectItemData",
|
||||
SetProperty = "set-property", // 设置node属性
|
||||
UpdateProperty = 'update-property', // 更新属性
|
||||
UpdateProperty = "update-property", // 更新属性
|
||||
}
|
||||
|
||||
export class PluginEvent {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import Vue from "vue"
|
||||
|
||||
export enum BusMsg {
|
||||
ShowPlace = 'ShowPlace',
|
||||
ShowPlace = "ShowPlace",
|
||||
RequestObjectData = "RequestObjectData",
|
||||
}
|
||||
|
||||
export default new Vue();
|
||||
|
@ -1,3 +1,6 @@
|
||||
// @ts-ignore
|
||||
import {v4} from "uuid"
|
||||
|
||||
export enum DataType {
|
||||
Number,
|
||||
String,
|
||||
@ -10,15 +13,20 @@ export enum DataType {
|
||||
NullOrUndefined,
|
||||
Array, // 暂时在控制台打印下
|
||||
Object,
|
||||
ObjectItem,
|
||||
Image, // 图片
|
||||
Engine,// 引擎的类型:cc.Node, cc.Sprite, cc.Label等。。。
|
||||
}
|
||||
|
||||
export class Info {
|
||||
public id: string | null = null;
|
||||
public type: DataType = DataType.Number;
|
||||
public data: any;
|
||||
public readonly: boolean = false;
|
||||
public path: Array<string> = [];// 属性对应的路径
|
||||
constructor() {
|
||||
this.id = v4();
|
||||
}
|
||||
}
|
||||
|
||||
export class TextData extends Info {
|
||||
@ -28,10 +36,15 @@ export class TextData extends Info {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ObjectItemRequestData {
|
||||
id: string | null;
|
||||
data: Property[];
|
||||
}
|
||||
|
||||
export class EngineData extends Info {
|
||||
public engineType: string = '';
|
||||
public engineUUID: string = '';
|
||||
public engineName: string = '';
|
||||
public engineType: string = "";
|
||||
public engineUUID: string = "";
|
||||
public engineName: string = "";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -53,18 +66,16 @@ export class ArrayData extends Info {
|
||||
}
|
||||
}
|
||||
|
||||
export class ObjectData extends Info {
|
||||
data: Array<Property> = [];
|
||||
export class ObjectDataItem extends Info {
|
||||
|
||||
}
|
||||
|
||||
export class ObjectData extends Info {
|
||||
data: string = "";// object的简单描述快照,类似chrome的console,{a:'fff',b:xxx}
|
||||
constructor() {
|
||||
super();
|
||||
this.type = DataType.Object;
|
||||
}
|
||||
|
||||
add(info: Property) {
|
||||
this.data.push(info);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class NullOrUndefinedData extends Info {
|
||||
@ -159,13 +170,13 @@ export class EnumData extends Info {
|
||||
|
||||
export class TreeData {
|
||||
active: boolean = true;
|
||||
uuid: string = '';
|
||||
name: string = '';
|
||||
uuid: string = "";
|
||||
name: string = "";
|
||||
children: Array<TreeData> = [];
|
||||
}
|
||||
|
||||
export class Property {
|
||||
public name: string = 'property';
|
||||
public name: string = "property";
|
||||
public value: Info = new Info();
|
||||
|
||||
constructor(name: string, info: Info) {
|
||||
@ -175,7 +186,7 @@ export class Property {
|
||||
}
|
||||
|
||||
export class Group {
|
||||
public name: string = 'group';
|
||||
public name: string = "group";
|
||||
public data: Array<Property> = [];
|
||||
|
||||
constructor(name: string) {
|
||||
@ -187,7 +198,7 @@ export class Group {
|
||||
}
|
||||
|
||||
sort() {
|
||||
let order = ['name', 'active', 'enabled', 'uuid', 'position', 'rotation', 'scale', 'anchor', 'size', 'color', 'opacity', 'skew', 'group'];
|
||||
let order = ["name", "active", "enabled", "uuid", "position", "rotation", "scale", "anchor", "size", "color", "opacity", "skew", "group"];
|
||||
let orderKeys: Array<Property> = [];
|
||||
let otherKeys: Array<Property> = [];
|
||||
this.data.forEach(property => {
|
||||
@ -204,86 +215,3 @@ export class Group {
|
||||
this.data = orderKeys.concat(otherKeys);
|
||||
}
|
||||
}
|
||||
|
||||
export const testData = [
|
||||
{
|
||||
name: "group1",
|
||||
uuid: 'node/comp uuid',
|
||||
data: [
|
||||
{name: "uuid", value: {type: DataType.String, data: 'abc', path: 'uuid'}},
|
||||
{name: "opacity", value: {type: DataType.Number, data: 100}},
|
||||
|
||||
{
|
||||
name: "size",
|
||||
value: {
|
||||
type: DataType.Vec2,
|
||||
data: [
|
||||
{name: "X", value: {type: DataType.Number, data: 100}},
|
||||
{name: "Y", value: {type: DataType.Number, data: 200}},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "position",
|
||||
value: {
|
||||
type: DataType.Vec3,
|
||||
data: [
|
||||
{name: "X", value: {type: DataType.Number, data: 100}},
|
||||
{name: "Y", value: {type: DataType.Number, data: 200}},
|
||||
{name: "Z", value: {type: DataType.Number, data: 300}},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "layout",
|
||||
value: {
|
||||
type: DataType.Enum,
|
||||
data: 1,
|
||||
values: [
|
||||
{name: "horizontal", value: 1},
|
||||
{name: "vertical", value: 2},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
value: {
|
||||
type: DataType.Text,
|
||||
data: 'aaaaaaaaafsf',
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "group2",
|
||||
data: [
|
||||
{
|
||||
name: "bool", value: {
|
||||
type: DataType.Bool,
|
||||
data: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
value: {
|
||||
type: DataType.Color,
|
||||
data: '#ff0000'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
value: {
|
||||
type: DataType.Array,
|
||||
data: [1, 2, 3, 4]
|
||||
}
|
||||
}, {
|
||||
name: 'object',
|
||||
value: {
|
||||
type: DataType.Object,
|
||||
data: {a: '11111111111111111111111111111111111111111111111111111111111', b: 2, c: 3}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -54,7 +54,7 @@ import {Component} from "vue-property-decorator";
|
||||
import properties from "./propertys.vue";
|
||||
import {Msg, Page, PluginEvent} from "@/core/types"
|
||||
import {connectBackground} from "@/devtools/connectBackground";
|
||||
import {EngineData, Info, TreeData} from "@/devtools/data";
|
||||
import {EngineData, Info, TreeData, ObjectData, ObjectItemRequestData} from "@/devtools/data";
|
||||
import Bus, {BusMsg} from "@/devtools/bus";
|
||||
|
||||
@Component({
|
||||
@ -82,6 +82,9 @@ export default class Index extends Vue {
|
||||
}
|
||||
timerID: number = 0;
|
||||
|
||||
|
||||
private requestList: Array<{ id: string, cb: Function }> = [];
|
||||
|
||||
created() {
|
||||
if (chrome && chrome.runtime) {
|
||||
this._initChromeRuntimeConnect();
|
||||
@ -94,6 +97,13 @@ export default class Index extends Vue {
|
||||
console.log(data)
|
||||
this._expand(data.engineUUID);
|
||||
})
|
||||
Bus.$on(BusMsg.RequestObjectData, (data: ObjectData, cb: Function) => {
|
||||
if (this.requestList.find(el => el.id === data.id)) {
|
||||
return
|
||||
}
|
||||
this.requestList.push({id: data.id, cb});
|
||||
this.sendMsgToContentScript(Msg.GetObjectItemData, data)
|
||||
});
|
||||
}
|
||||
|
||||
_expand(uuid: string) {
|
||||
@ -185,7 +195,6 @@ export default class Index extends Vue {
|
||||
return;
|
||||
}
|
||||
if (data.target === Page.Devtools) {
|
||||
debugger
|
||||
console.log(`[Devtools] ${JSON.stringify(data)}`);
|
||||
PluginEvent.finish(data);
|
||||
let eventData: any = data.data;
|
||||
@ -214,6 +223,17 @@ export default class Index extends Vue {
|
||||
debugger
|
||||
break
|
||||
}
|
||||
case Msg.GetObjectItemData: {
|
||||
let eventData: ObjectItemRequestData = data.data as ObjectItemRequestData;
|
||||
if (eventData.id !== null) {
|
||||
let findIndex = this.requestList.findIndex(el => el.id === eventData.id)
|
||||
if (findIndex > -1) {
|
||||
let del = this.requestList.splice(findIndex, 1)[0];
|
||||
del.cb(eventData.data);
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -249,7 +269,7 @@ export default class Index extends Vue {
|
||||
this.selectedUUID = data.uuid;
|
||||
let uuid = data.uuid;
|
||||
if (uuid !== undefined) {
|
||||
this.runToContentScript(Msg.NodeInfo, uuid);
|
||||
this.sendMsgToContentScript(Msg.NodeInfo, uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +278,7 @@ export default class Index extends Vue {
|
||||
this.timerID = setInterval(() => {
|
||||
this.onBtnClickUpdateTree();
|
||||
if (this.selectedUUID) {
|
||||
this.runToContentScript(Msg.NodeInfo, this.selectedUUID);
|
||||
this.sendMsgToContentScript(Msg.NodeInfo, this.selectedUUID);
|
||||
}
|
||||
}, 300);
|
||||
} else {
|
||||
@ -266,7 +286,7 @@ export default class Index extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
runToContentScript(msg: Msg, data?: any) {
|
||||
sendMsgToContentScript(msg: Msg, data?: any) {
|
||||
if (!chrome || !chrome.devtools) {
|
||||
console.log("环境异常,无法执行函数");
|
||||
return;
|
||||
@ -296,16 +316,15 @@ export default class Index extends Vue {
|
||||
}
|
||||
|
||||
onBtnClickUpdateTree() {
|
||||
this.runToContentScript(Msg.TreeInfo);
|
||||
this.sendMsgToContentScript(Msg.TreeInfo);
|
||||
}
|
||||
|
||||
onBtnClickUpdatePage() {
|
||||
debugger
|
||||
this.runToContentScript(Msg.Support);
|
||||
this.sendMsgToContentScript(Msg.Support);
|
||||
}
|
||||
|
||||
onMemoryTest() {
|
||||
this.runToContentScript(Msg.MemoryInfo);
|
||||
this.sendMsgToContentScript(Msg.MemoryInfo);
|
||||
}
|
||||
|
||||
onNodeExpand(data: TreeData) {
|
||||
|
@ -76,7 +76,6 @@
|
||||
</div>
|
||||
<!-- <div v-if="isArrayOrObject()" class="array-object">-->
|
||||
<!-- <div class="text">-->
|
||||
<!-- {{ valueString() }}-->
|
||||
<!-- </div>-->
|
||||
<!-- <el-button @click="onShowValueInConsole">log</el-button>-->
|
||||
<!-- </div>-->
|
||||
@ -100,14 +99,17 @@
|
||||
<div class="name">{{ value.engineName }}</div>
|
||||
<el-button @click="onPlaceInTree" type="primary" icon="el-icon-place"></el-button>
|
||||
</div>
|
||||
<div v-if="isArrayOrObject()&&fold" class="arrayOrObjectDesc">
|
||||
{{ value.data }}
|
||||
</div>
|
||||
<div class="slot">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isArrayOrObject()">
|
||||
<div v-show="!fold" style="display: flex;flex-direction: column;">
|
||||
<ui-prop v-for="(arr,index) in value.data"
|
||||
<div v-show="!fold&&subData" style="display: flex;flex-direction: column;">
|
||||
<ui-prop v-for="(arr,index) in subData"
|
||||
:key="index"
|
||||
:indent="indent+1"
|
||||
:value="arr.value"
|
||||
@ -123,7 +125,7 @@
|
||||
|
||||
import Vue from "vue"
|
||||
import {Component, Prop} from "vue-property-decorator"
|
||||
import {DataType, Info, EngineData} from "../data"
|
||||
import {DataType, Info, EngineData, Property} from "../data"
|
||||
import {connectBackground} from "@/devtools/connectBackground";
|
||||
import {Msg} from "@/core/types";
|
||||
import Bus, {BusMsg} from "../bus"
|
||||
@ -228,17 +230,20 @@ export default class UiProp extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
private fold = false;
|
||||
private fold = true;
|
||||
|
||||
private subData: Property[] | null = null;
|
||||
|
||||
onClickFold() {
|
||||
this.fold = !this.fold;
|
||||
}
|
||||
if (this.isObject() && this.fold && !this.subData) {
|
||||
// 请求object的item数据
|
||||
Bus.$emit(BusMsg.RequestObjectData, this.value, (info: Property[]) => {
|
||||
|
||||
valueString() {
|
||||
try {
|
||||
return JSON.stringify(this.value.data)
|
||||
} catch (e) {
|
||||
return ""
|
||||
this.fold = false;
|
||||
this.subData = info;
|
||||
})
|
||||
} else {
|
||||
this.fold = !this.fold;
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,6 +378,13 @@ export default class UiProp extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
.arrayOrObjectDesc {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.engine {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
@ -3,12 +3,14 @@ import {
|
||||
ArrayData,
|
||||
BoolData,
|
||||
ColorData,
|
||||
DataType, EngineData,
|
||||
Group, ImageData,
|
||||
DataType,
|
||||
EngineData,
|
||||
Group,
|
||||
ImageData,
|
||||
Info,
|
||||
NullOrUndefinedData,
|
||||
NumberData,
|
||||
ObjectData,
|
||||
ObjectData, ObjectItemRequestData,
|
||||
Property,
|
||||
StringData,
|
||||
TreeData,
|
||||
@ -16,9 +18,9 @@ import {
|
||||
Vec3Data
|
||||
} from "@/devtools/data";
|
||||
import {Msg, Page, PluginEvent} from "@/core/types"
|
||||
import {BuildDataOptions, BuildImageOptions, BuildVecOptions} from "@/inject/types";
|
||||
import {BuildArrayOptions, BuildImageOptions, BuildObjectOptions, BuildVecOptions} from "@/inject/types";
|
||||
|
||||
declare var cc: any;
|
||||
declare const cc: any;
|
||||
|
||||
|
||||
class CCInspector {
|
||||
@ -72,6 +74,24 @@ class CCInspector {
|
||||
this.sendMsgToContent(Msg.UpdateProperty, data);
|
||||
break;
|
||||
}
|
||||
case Msg.GetObjectItemData: {
|
||||
const data: ObjectData = pluginEvent.data;
|
||||
let val = this.getValue(data.path);
|
||||
if (val) {
|
||||
let itemData: Property[] = this._buildObjectItemData({
|
||||
data: data,
|
||||
path: data.path,
|
||||
value: val,
|
||||
filterKey: false,
|
||||
});
|
||||
let result: ObjectItemRequestData = {
|
||||
id: data.id,
|
||||
data: itemData,
|
||||
}
|
||||
this.sendMsgToContent(Msg.GetObjectItemData, result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -248,7 +268,7 @@ class CCInspector {
|
||||
return null;
|
||||
}
|
||||
|
||||
_genInfoData(node: any, key: string | number, path: Array<string>) {
|
||||
_genInfoData(node: any, key: string | number, path: Array<string>, filterKey = true) {
|
||||
let propertyValue = node[key];
|
||||
let info = null;
|
||||
switch (typeof propertyValue) {
|
||||
@ -316,7 +336,7 @@ class CCInspector {
|
||||
data: new ObjectData(),
|
||||
path: path,
|
||||
value: propertyValue,
|
||||
keys: Object.keys(propertyValue),
|
||||
filterKey: filterKey,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -333,26 +353,12 @@ class CCInspector {
|
||||
return info;
|
||||
}
|
||||
|
||||
_buildArrayData(options: BuildDataOptions) {
|
||||
return this._buildObjectOrArrayData(options);
|
||||
}
|
||||
|
||||
_buildObjectData(options: BuildDataOptions) {
|
||||
// todo 只返回一级key,更深层级的key需要的时候,再获取,防止circle object导致的死循环
|
||||
|
||||
}
|
||||
|
||||
_buildObjectOrArrayData(options: BuildDataOptions) {
|
||||
let propertyValue: Object = options.value;
|
||||
let path: Array<string> = options.path;
|
||||
let data: ObjectData | ArrayData = options.data;
|
||||
let keys: Array<string | number> = options.keys;
|
||||
// 剔除_开头的属性
|
||||
_buildArrayData({value, path, data, keys}: BuildArrayOptions) {
|
||||
keys = keys.filter(key => !key.toString().startsWith("_"));
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
let propPath = path.concat(key.toString());
|
||||
let itemData = this._genInfoData(propertyValue, key, propPath);
|
||||
let itemData = this._genInfoData(value, key, propPath);
|
||||
if (itemData) {
|
||||
data.add(new Property(key.toString(), itemData))
|
||||
}
|
||||
@ -360,6 +366,57 @@ class CCInspector {
|
||||
return data;
|
||||
}
|
||||
|
||||
_buildObjectItemData({value, path, data, filterKey}: BuildObjectOptions): Property[] {
|
||||
let keys = Object.keys(value);
|
||||
if (filterKey) {
|
||||
keys = this.filterKeys(keys);// 不再进行开发者定义的数据
|
||||
}
|
||||
let ret: Property[] = []
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
let propPath = path.concat(key.toString());
|
||||
let itemData = this._genInfoData(value, key, propPath, filterKey);
|
||||
if (itemData) {
|
||||
ret.push(new Property(key, itemData))
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
filterKeys(keys: string[]) {
|
||||
// 剔除_开头的属性
|
||||
return keys.filter(key => !key.toString().startsWith("_"));
|
||||
}
|
||||
|
||||
_buildObjectData({value, path, data, filterKey}: BuildObjectOptions) {
|
||||
let keys = Object.keys(value);
|
||||
if (filterKey) {
|
||||
keys = this.filterKeys(keys)
|
||||
}
|
||||
// 只返回一级key,更深层级的key需要的时候,再获取,防止circle object导致的死循环
|
||||
let desc: Record<string, any> = {};
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
let propPath = path.concat(key.toString());
|
||||
let propValue = (value as any)[key];
|
||||
let keyDesc = "";
|
||||
if (Array.isArray(propValue)) {
|
||||
// 只收集一级key
|
||||
propValue.forEach(item => {
|
||||
|
||||
})
|
||||
keyDesc = `(${propValue.length}) [...]`
|
||||
} else if (typeof propValue === "object") {
|
||||
keyDesc = `${propValue.constructor.name} {...}`;
|
||||
} else {
|
||||
keyDesc = propValue;
|
||||
}
|
||||
desc[key] = keyDesc;
|
||||
}
|
||||
data.data = JSON.stringify(desc);
|
||||
return data;
|
||||
}
|
||||
|
||||
private getCompName(comp: any): string {
|
||||
const nameKeys = [
|
||||
"__classname__", // 2.4.0 验证通过
|
||||
@ -491,6 +548,19 @@ class CCInspector {
|
||||
}
|
||||
}
|
||||
|
||||
getValue(path: string[]) {
|
||||
let target = this.inspectorGameMemoryStorage;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
let key = path[i];
|
||||
if (target.hasOwnProperty(key)) {
|
||||
target = target[key]
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
onMemoryInfo() {
|
||||
this.sendMsgToContent(Msg.MemoryInfo, {
|
||||
|
@ -1,10 +1,17 @@
|
||||
import {ArrayData, ImageData, ObjectData, Vec2Data, Vec3Data} from "@/devtools/data";
|
||||
|
||||
export interface BuildDataOptions {
|
||||
export interface BuildObjectOptions {
|
||||
path: string[];
|
||||
value: Object;
|
||||
data: ObjectData | ArrayData;
|
||||
keys: string[] | number[];
|
||||
data: ObjectData;
|
||||
filterKey:boolean;
|
||||
}
|
||||
|
||||
export interface BuildArrayOptions {
|
||||
path: string[];
|
||||
value: Object;
|
||||
data: ArrayData;
|
||||
keys: number[];
|
||||
}
|
||||
|
||||
export interface BuildVecOptions {
|
||||
|
Loading…
x
Reference in New Issue
Block a user