phecda-vue 4.0.2 → 4.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ import { WebPhecda, Construct, Events } from 'phecda-web';
2
+ export * from 'phecda-web';
3
+ import { App, Ref, UnwrapNestedRefs, WatchOptions } from 'vue';
4
+
5
+ declare const phecdaSymbol: unique symbol;
6
+ declare class VuePhecda extends WebPhecda {
7
+ vueApp: App;
8
+ install(app: App): void;
9
+ }
10
+ declare function createPhecda(): VuePhecda;
11
+
12
+ declare const RawSymbol: unique symbol;
13
+ type Raw<T> = T & {
14
+ [RawSymbol]: true;
15
+ };
16
+ type ReplaceInstanceValues<I> = {
17
+ [P in keyof I]: I[P] extends (...args: any[]) => any ? I[P] : I[P] extends Raw<infer O> ? O : Ref<I[P]>;
18
+ };
19
+ type SchemaToObj<S> = {
20
+ [P in keyof S]: S[P] extends object ? SchemaToObj<S[P]> : (S[P] extends string ? any : S[P]);
21
+ };
22
+
23
+ declare function useRaw<T extends Construct>(model: T): InstanceType<T>;
24
+ declare function usePhecda(): VuePhecda;
25
+ declare function getPhecda(phecda?: VuePhecda): VuePhecda;
26
+ declare function useEvent<Key extends keyof Events>(eventName: Key, cb: (event: Events[Key]) => void): {
27
+ emit: (arg: Events[Key]) => void;
28
+ cancel: () => void;
29
+ };
30
+ declare function useR<T extends Construct>(model: T): UnwrapNestedRefs<InstanceType<T>>;
31
+ declare function getR<T extends Construct>(model: T, phecda?: VuePhecda): UnwrapNestedRefs<InstanceType<T>>;
32
+ declare function useV<T extends Construct>(model: T): ReplaceInstanceValues<InstanceType<T>>;
33
+ declare function getV<T extends Construct>(model: T, phecda?: VuePhecda): ReplaceInstanceValues<InstanceType<T>>;
34
+
35
+ declare function Shallow(model: any): void;
36
+ declare function WatchEffect(option?: WatchOptions): (proto: any, key: string) => void;
37
+
38
+ declare function markRaw<T extends object>(value: T): Raw<T>;
39
+ declare function createSharedReactive<F extends (...args: any) => any>(composable: F): () => ReturnType<F>;
40
+
41
+ export { type Raw, RawSymbol, type ReplaceInstanceValues, type SchemaToObj, Shallow, VuePhecda, WatchEffect, createPhecda, createSharedReactive, getPhecda, getR, getV, markRaw, phecdaSymbol, useEvent, usePhecda, useR, useRaw, useV };
package/dist/index.d.ts CHANGED
@@ -32,10 +32,10 @@ declare function getR<T extends Construct>(model: T, phecda?: VuePhecda): Unwrap
32
32
  declare function useV<T extends Construct>(model: T): ReplaceInstanceValues<InstanceType<T>>;
33
33
  declare function getV<T extends Construct>(model: T, phecda?: VuePhecda): ReplaceInstanceValues<InstanceType<T>>;
34
34
 
35
- declare function Shallow(isShallow?: boolean): (model: any) => void;
35
+ declare function Shallow(model: any): void;
36
36
  declare function WatchEffect(option?: WatchOptions): (proto: any, key: string) => void;
37
37
 
38
38
  declare function markRaw<T extends object>(value: T): Raw<T>;
39
39
  declare function createSharedReactive<F extends (...args: any) => any>(composable: F): () => ReturnType<F>;
40
40
 
41
- export { Raw, RawSymbol, ReplaceInstanceValues, SchemaToObj, Shallow, VuePhecda, WatchEffect, createPhecda, createSharedReactive, getPhecda, getR, getV, markRaw, phecdaSymbol, useEvent, usePhecda, useR, useRaw, useV };
41
+ export { type Raw, RawSymbol, type ReplaceInstanceValues, type SchemaToObj, Shallow, VuePhecda, WatchEffect, createPhecda, createSharedReactive, getPhecda, getR, getV, markRaw, phecdaSymbol, useEvent, usePhecda, useR, useRaw, useV };
package/dist/index.js CHANGED
@@ -44,21 +44,335 @@ __reExport(src_exports, require("phecda-web"), module.exports);
44
44
  // src/core.ts
45
45
  var import_vue = require("vue");
46
46
  var import_phecda_web = require("phecda-web");
47
+ var import_devtools_api = require("@vue/devtools-api");
48
+
49
+ // src/devtools.ts
50
+ var componentStateTypes = [];
51
+ var MUTATIONS_LAYER_ID = "phecda-vue:mutations";
52
+ var INSPECTOR_ID = "phecda-vue";
53
+ function toastMessage(message, type) {
54
+ const piniaMessage = `[phecda-vue]: ${message}`;
55
+ if (type === "error") console.error(piniaMessage);
56
+ else if (type === "warn") console.warn(piniaMessage);
57
+ else console.log(piniaMessage);
58
+ }
59
+ __name(toastMessage, "toastMessage");
60
+ var USE_DEVTOOLS = process.env.NODE_ENV === "development" && typeof window;
61
+
62
+ // src/core.ts
47
63
  var phecdaSymbol = Symbol(process.env.NODE_ENV === "development" ? "phecda-vue" : void 0);
48
64
  var VuePhecda = class extends import_phecda_web.WebPhecda {
65
+ static {
66
+ __name(this, "VuePhecda");
67
+ }
49
68
  vueApp;
50
69
  install(app) {
51
70
  app.provide(phecdaSymbol, this);
52
71
  this.vueApp = app;
72
+ if (USE_DEVTOOLS) {
73
+ (0, import_devtools_api.setupDevtoolsPlugin)({
74
+ settings: {
75
+ sendTrigger: {
76
+ label: "send DebuggerEvent in onTrigger to timeline",
77
+ type: "boolean",
78
+ defaultValue: false
79
+ },
80
+ triggerEventSync: {
81
+ label: "send trigger event to timeline Synchronously",
82
+ type: "boolean",
83
+ defaultValue: false
84
+ },
85
+ sendUpdate: {
86
+ label: "Record view update caused by model to timeline",
87
+ type: "boolean",
88
+ defaultValue: false
89
+ }
90
+ },
91
+ id: "dev.esm.phecda",
92
+ label: "Phecda Vue",
93
+ packageName: "phecda",
94
+ // @todo
95
+ // logo: 'https://phecda.vuejs.org/logo.svg',
96
+ // homepage: 'https://phecda.vuejs.org',
97
+ componentStateTypes,
98
+ app
99
+ }, (api) => {
100
+ const now = typeof api.now === "function" ? api.now.bind(api) : Date.now;
101
+ api.addTimelineLayer({
102
+ id: MUTATIONS_LAYER_ID,
103
+ label: "Phecda Vue",
104
+ color: 9089261
105
+ });
106
+ const watchModule = /* @__PURE__ */ __name((tag) => {
107
+ (0, import_vue.watch)(this.get(tag), (data) => {
108
+ const { sendUpdate } = api.getSettings();
109
+ if (sendUpdate) {
110
+ api.addTimelineEvent({
111
+ layerId: MUTATIONS_LAYER_ID,
112
+ event: {
113
+ time: now(),
114
+ title: "Update",
115
+ subtitle: String(tag),
116
+ data: {
117
+ ...data
118
+ }
119
+ }
120
+ });
121
+ }
122
+ api.notifyComponentUpdate();
123
+ api.sendInspectorState(INSPECTOR_ID);
124
+ }, {
125
+ deep: true,
126
+ onTrigger(event) {
127
+ const { triggerEventSync, sendTrigger } = api.getSettings();
128
+ if (sendTrigger && !triggerEventSync) {
129
+ api.addTimelineEvent({
130
+ layerId: MUTATIONS_LAYER_ID,
131
+ event: {
132
+ time: now(),
133
+ title: "Trigger",
134
+ subtitle: String(tag),
135
+ data: event
136
+ }
137
+ });
138
+ }
139
+ }
140
+ });
141
+ (0, import_vue.watch)(this.get(tag), () => {
142
+ }, {
143
+ deep: true,
144
+ flush: "sync",
145
+ onTrigger(event) {
146
+ const { triggerEventSync, sendTrigger } = api.getSettings();
147
+ if (sendTrigger && triggerEventSync) {
148
+ api.addTimelineEvent({
149
+ layerId: MUTATIONS_LAYER_ID,
150
+ event: {
151
+ time: now(),
152
+ title: "Trigger",
153
+ subtitle: String(tag),
154
+ data: event
155
+ }
156
+ });
157
+ }
158
+ }
159
+ });
160
+ }, "watchModule");
161
+ for (const tag in this.state) watchModule(tag);
162
+ this.on("Instantiate", ({ tag }) => {
163
+ api.sendInspectorTree(INSPECTOR_ID);
164
+ watchModule(tag);
165
+ });
166
+ this.on("*", (type, event) => {
167
+ api.addTimelineEvent({
168
+ layerId: MUTATIONS_LAYER_ID,
169
+ event: {
170
+ time: now(),
171
+ title: type,
172
+ subtitle: event.tag,
173
+ data: event
174
+ }
175
+ });
176
+ });
177
+ api.addInspector({
178
+ id: INSPECTOR_ID,
179
+ label: "Phecda Vue",
180
+ icon: "storage",
181
+ treeFilterPlaceholder: "Search",
182
+ actions: [
183
+ {
184
+ icon: "content_copy",
185
+ action: /* @__PURE__ */ __name(async () => {
186
+ toastMessage("Global state copied to clipboard.");
187
+ await navigator.clipboard.writeText(this.serialize());
188
+ }, "action"),
189
+ tooltip: "Serialize and copy the state"
190
+ },
191
+ {
192
+ icon: "content_paste",
193
+ action: /* @__PURE__ */ __name(async () => {
194
+ toastMessage("Global state pasted from clipboard.");
195
+ await this.load(await navigator.clipboard.readText());
196
+ api.sendInspectorTree(INSPECTOR_ID);
197
+ api.sendInspectorState(INSPECTOR_ID);
198
+ }, "action"),
199
+ tooltip: "Replace the state with the content of your clipboard"
200
+ }
201
+ ],
202
+ nodeActions: [
203
+ {
204
+ icon: "restore",
205
+ tooltip: "Reset the state ",
206
+ action: /* @__PURE__ */ __name((nodeId) => {
207
+ this.reset(this.getModel(nodeId));
208
+ }, "action")
209
+ }
210
+ ]
211
+ });
212
+ api.on.inspectComponent((payload) => {
213
+ const proxy = payload.componentInstance && payload.componentInstance.proxy;
214
+ if (proxy && proxy._phecda_vue) {
215
+ for (const tag in proxy._phecda_vue) {
216
+ payload.instanceData.state.push({
217
+ type: "phecda-vue",
218
+ key: tag,
219
+ editable: true,
220
+ value: proxy._phecda_vue[tag]
221
+ });
222
+ }
223
+ }
224
+ });
225
+ api.on.getInspectorTree((payload) => {
226
+ if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
227
+ payload.rootNodes = Object.keys(this.state).map((tag) => {
228
+ return {
229
+ id: tag,
230
+ label: tag
231
+ };
232
+ });
233
+ }
234
+ });
235
+ api.on.getInspectorState((payload) => {
236
+ if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
237
+ if (this.has(payload.nodeId)) {
238
+ const instance = this.get(payload.nodeId);
239
+ payload.state = {
240
+ state: [],
241
+ methods: [],
242
+ getters: [],
243
+ internals: [],
244
+ memory: Object.entries(this.memory[payload.nodeId] || {}).map(([key, value]) => {
245
+ return {
246
+ editable: false,
247
+ key,
248
+ value
249
+ };
250
+ })
251
+ };
252
+ Object.entries(instance).forEach(([key, value]) => {
253
+ if (this.modelMap.has(value)) {
254
+ const tag = String((0, import_phecda_web.getTag)((0, import_vue.toRaw)(value)));
255
+ payload.state.state.unshift({
256
+ editable: false,
257
+ key,
258
+ value: `[PV] ${tag}`,
259
+ raw: `Phecda Vue Module [${tag}]`
260
+ });
261
+ return;
262
+ }
263
+ if (!key.startsWith("__")) payload.state.state.push({
264
+ editable: true,
265
+ key,
266
+ value
267
+ });
268
+ else payload.state.internals.push({
269
+ editable: false,
270
+ key,
271
+ value
272
+ });
273
+ });
274
+ getAllGetters(instance).forEach((item) => {
275
+ payload.state.getters.push({
276
+ editable: false,
277
+ key: item,
278
+ value: instance[item]
279
+ });
280
+ });
281
+ getAllMethods(instance).forEach((item) => {
282
+ if (typeof instance[item] === "function") payload.state[item.startsWith("__") ? "internals" : "methods"].push({
283
+ editable: false,
284
+ key: item,
285
+ value: Object.getPrototypeOf(instance)[item]
286
+ });
287
+ });
288
+ }
289
+ }
290
+ });
291
+ api.on.editInspectorState((payload) => {
292
+ if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
293
+ const state = this.get(payload.nodeId);
294
+ const { path } = payload;
295
+ payload.set(state, path, payload.state.value);
296
+ }
297
+ });
298
+ api.on.editComponentState((payload) => {
299
+ const { path, type } = payload;
300
+ if (type === "phecda-vue") payload.set(this.get(path.shift()), path, payload.state.value);
301
+ });
302
+ });
303
+ }
53
304
  }
54
305
  };
55
- __name(VuePhecda, "VuePhecda");
56
306
  function createPhecda() {
57
- return new VuePhecda((instance) => {
58
- return (0, import_phecda_web.bindMethod)((0, import_phecda_web.get)(instance, "shallow") ? (0, import_vue.shallowReactive)(instance) : (0, import_vue.reactive)(instance));
307
+ const phecda = new VuePhecda("vue", (instance) => {
308
+ return (0, import_phecda_web.bindMethod)((0, import_phecda_web.get)(instance, "shallow") ? (0, import_vue.shallowReactive)(instance) : (0, import_vue.reactive)(instance), USE_DEVTOOLS ? (instance2, key) => {
309
+ const cb = instance2[key].bind(instance2);
310
+ if (findPrototypeWithMethod(instance2, key).constructor.name === "Object") return cb;
311
+ const tag = (0, import_phecda_web.getTag)(instance2);
312
+ return (...args) => {
313
+ const name = `${tag}.${key}`;
314
+ phecda.emit(`Invoke ${name}`, {
315
+ args,
316
+ tag,
317
+ key
318
+ });
319
+ const ret = cb(...args);
320
+ if (ret instanceof Promise) ret.then(() => phecda.emit(`End ${name}(Async)`, {
321
+ args,
322
+ tag,
323
+ key
324
+ }));
325
+ else phecda.emit(`End ${name}`, {
326
+ args,
327
+ tag,
328
+ key
329
+ });
330
+ return ret;
331
+ };
332
+ } : void 0);
59
333
  });
334
+ return phecda;
60
335
  }
61
336
  __name(createPhecda, "createPhecda");
337
+ function findPrototypeWithMethod(instance, method) {
338
+ let proto = Object.getPrototypeOf(instance);
339
+ while (proto) {
340
+ if (proto.hasOwnProperty(method)) return proto;
341
+ proto = Object.getPrototypeOf(proto);
342
+ }
343
+ return null;
344
+ }
345
+ __name(findPrototypeWithMethod, "findPrototypeWithMethod");
346
+ function getAllMethods(obj) {
347
+ const methods = /* @__PURE__ */ new Set();
348
+ obj = Object.getPrototypeOf(obj);
349
+ while (obj.constructor.name !== "Object") {
350
+ Object.getOwnPropertyNames(obj).forEach((prop) => {
351
+ const propDescriptor = Object.getOwnPropertyDescriptor(obj, prop);
352
+ if (typeof propDescriptor.value === "function" && prop !== "constructor") methods.add(prop);
353
+ });
354
+ obj = Object.getPrototypeOf(obj);
355
+ }
356
+ return [
357
+ ...methods
358
+ ];
359
+ }
360
+ __name(getAllMethods, "getAllMethods");
361
+ function getAllGetters(obj) {
362
+ const getters = /* @__PURE__ */ new Set();
363
+ obj = Object.getPrototypeOf(obj);
364
+ while (obj.constructor.name !== "Object") {
365
+ Object.getOwnPropertyNames(obj).forEach((prop) => {
366
+ const propDescriptor = Object.getOwnPropertyDescriptor(obj, prop);
367
+ if (typeof propDescriptor.get === "function") getters.add(prop);
368
+ });
369
+ obj = Object.getPrototypeOf(obj);
370
+ }
371
+ return [
372
+ ...getters
373
+ ];
374
+ }
375
+ __name(getAllGetters, "getAllGetters");
62
376
 
63
377
  // src/composable.ts
64
378
  var import_phecda_web2 = require("phecda-web");
@@ -101,22 +415,29 @@ function useRaw(model) {
101
415
  }
102
416
  __name(useRaw, "useRaw");
103
417
  function usePhecda() {
104
- if (!(0, import_vue3.hasInjectionContext)())
105
- throw new Error("[phecda-vue]: use hook inside component setup function");
418
+ if (!(0, import_vue3.hasInjectionContext)()) throw new Error("[phecda-vue]: use hook inside component setup function");
106
419
  const activePhecda = (0, import_vue3.inject)(phecdaSymbol);
107
- if (!activePhecda)
108
- throw new Error("[phecda-vue]: must install the vue plugin ");
109
- if (!cacheMap.has(activePhecda))
110
- cacheMap.set(activePhecda, (0, import_phecda_web2.bindMethod)(activePhecda));
420
+ if (!activePhecda) throw new Error("[phecda-vue]: must install the vue plugin ");
421
+ if (!cacheMap.has(activePhecda)) cacheMap.set(activePhecda, (0, import_phecda_web2.bindMethod)(activePhecda));
111
422
  return cacheMap.get(activePhecda);
112
423
  }
113
424
  __name(usePhecda, "usePhecda");
425
+ function setStateToComponent(model) {
426
+ if (USE_DEVTOOLS) {
427
+ const currentInstance = (0, import_vue3.getCurrentInstance)();
428
+ if (currentInstance && currentInstance.proxy) {
429
+ const vm = currentInstance.proxy;
430
+ const cache = "_phecda_vue" in vm ? vm._phecda_vue : vm._phecda_vue = {};
431
+ const tag = (0, import_phecda_web2.getTag)(model);
432
+ cache[tag] = usePhecda().init(model);
433
+ }
434
+ }
435
+ }
436
+ __name(setStateToComponent, "setStateToComponent");
114
437
  function getPhecda(phecda) {
115
- const activePhecda = phecda || (0, import_phecda_web2.getDefaultPhecda)();
116
- if (!activePhecda)
117
- throw new Error("[phecda-vue]: manually inject the phecda instance if there is no default phecda");
118
- if (!cacheMap.has(activePhecda))
119
- cacheMap.set(activePhecda, (0, import_phecda_web2.bindMethod)(activePhecda));
438
+ const activePhecda = phecda || (0, import_phecda_web2.getDefaultPhecda)("vue");
439
+ if (!activePhecda) throw new Error("[phecda-vue]: manually inject the phecda instance if there is no default phecda");
440
+ if (!cacheMap.has(activePhecda)) cacheMap.set(activePhecda, (0, import_phecda_web2.bindMethod)(activePhecda));
120
441
  return cacheMap.get(activePhecda);
121
442
  }
122
443
  __name(getPhecda, "getPhecda");
@@ -126,12 +447,13 @@ function useEvent(eventName, cb) {
126
447
  });
127
448
  import_phecda_web2.emitter.on(eventName, cb);
128
449
  return {
129
- emit: (arg) => import_phecda_web2.emitter.emit(eventName, arg),
130
- cancel: () => import_phecda_web2.emitter.off(eventName, cb)
450
+ emit: /* @__PURE__ */ __name((arg) => import_phecda_web2.emitter.emit(eventName, arg), "emit"),
451
+ cancel: /* @__PURE__ */ __name(() => import_phecda_web2.emitter.off(eventName, cb), "cancel")
131
452
  };
132
453
  }
133
454
  __name(useEvent, "useEvent");
134
455
  function useR(model) {
456
+ setStateToComponent(model);
135
457
  return usePhecda().init(model);
136
458
  }
137
459
  __name(useR, "useR");
@@ -140,19 +462,16 @@ function getR(model, phecda) {
140
462
  }
141
463
  __name(getR, "getR");
142
464
  function useV(model) {
465
+ setStateToComponent(model);
143
466
  const instance = usePhecda().init(model);
144
- if (cacheMap.has(instance))
145
- return cacheMap.get(instance);
467
+ if (cacheMap.has(instance)) return cacheMap.get(instance);
146
468
  const cache = {};
147
469
  const proxy = new Proxy(instance, {
148
470
  get(target, key) {
149
- if (typeof target[key] === "function")
150
- return target[key];
151
- if (target[key]?.__v_skip)
152
- return target[key];
471
+ if (typeof target[key] === "function") return target[key];
472
+ if (target[key]?.__v_skip) return target[key];
153
473
  const cacheRef = cache[key];
154
- if (cacheRef && cacheRef.r)
155
- return cacheRef();
474
+ if (cacheRef && cacheRef.r) return cacheRef();
156
475
  cache[key] = createSharedReactive(() => {
157
476
  return (0, import_vue3.toRef)(target, key);
158
477
  });
@@ -168,18 +487,14 @@ function useV(model) {
168
487
  __name(useV, "useV");
169
488
  function getV(model, phecda) {
170
489
  const instance = getPhecda(phecda).init(model);
171
- if (cacheMap.has(instance))
172
- return cacheMap.get(instance);
490
+ if (cacheMap.has(instance)) return cacheMap.get(instance);
173
491
  const cache = {};
174
492
  const proxy = new Proxy(instance, {
175
493
  get(target, key) {
176
- if (typeof target[key] === "function")
177
- return target[key];
178
- if (target[key]?.__v_skip)
179
- return target[key];
494
+ if (typeof target[key] === "function") return target[key];
495
+ if (target[key]?.__v_skip) return target[key];
180
496
  const cacheRef = cache[key];
181
- if (cacheRef && cacheRef.r)
182
- return cacheRef();
497
+ if (cacheRef && cacheRef.r) return cacheRef();
183
498
  cache[key] = createSharedReactive(() => {
184
499
  return (0, import_vue3.toRef)(target, key);
185
500
  });
@@ -197,10 +512,8 @@ __name(getV, "getV");
197
512
  // src/decorator.ts
198
513
  var import_phecda_web3 = require("phecda-web");
199
514
  var import_vue4 = require("vue");
200
- function Shallow(isShallow = true) {
201
- return (model) => {
202
- (0, import_phecda_web3.set)(model.prototype, "shallow", isShallow);
203
- };
515
+ function Shallow(model) {
516
+ (0, import_phecda_web3.set)(model.prototype, "shallow", true);
204
517
  }
205
518
  __name(Shallow, "Shallow");
206
519
  function WatchEffect(option) {
@@ -209,8 +522,7 @@ function WatchEffect(option) {
209
522
  let stopHandler;
210
523
  (0, import_phecda_web3.setHandler)(proto, key, {
211
524
  init(instance) {
212
- if (typeof instance[key] !== "function")
213
- throw new Error("WatchEffect must decorate function");
525
+ if (typeof instance[key] !== "function") throw new Error("WatchEffect must decorate function");
214
526
  stopHandler = (0, import_vue4.watchEffect)(instance[key].bind(instance), option);
215
527
  },
216
528
  unmount() {
package/dist/index.mjs CHANGED
@@ -5,27 +5,341 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
5
5
  export * from "phecda-web";
6
6
 
7
7
  // src/core.ts
8
- import { reactive, shallowReactive } from "vue";
9
- import { WebPhecda, bindMethod, get } from "phecda-web";
8
+ import { reactive, shallowReactive, toRaw, watch } from "vue";
9
+ import { WebPhecda, bindMethod, get, getTag } from "phecda-web";
10
+ import { setupDevtoolsPlugin } from "@vue/devtools-api";
11
+
12
+ // src/devtools.ts
13
+ var componentStateTypes = [];
14
+ var MUTATIONS_LAYER_ID = "phecda-vue:mutations";
15
+ var INSPECTOR_ID = "phecda-vue";
16
+ function toastMessage(message, type) {
17
+ const piniaMessage = `[phecda-vue]: ${message}`;
18
+ if (type === "error") console.error(piniaMessage);
19
+ else if (type === "warn") console.warn(piniaMessage);
20
+ else console.log(piniaMessage);
21
+ }
22
+ __name(toastMessage, "toastMessage");
23
+ var USE_DEVTOOLS = process.env.NODE_ENV === "development" && typeof window;
24
+
25
+ // src/core.ts
10
26
  var phecdaSymbol = Symbol(process.env.NODE_ENV === "development" ? "phecda-vue" : void 0);
11
27
  var VuePhecda = class extends WebPhecda {
28
+ static {
29
+ __name(this, "VuePhecda");
30
+ }
12
31
  vueApp;
13
32
  install(app) {
14
33
  app.provide(phecdaSymbol, this);
15
34
  this.vueApp = app;
35
+ if (USE_DEVTOOLS) {
36
+ setupDevtoolsPlugin({
37
+ settings: {
38
+ sendTrigger: {
39
+ label: "send DebuggerEvent in onTrigger to timeline",
40
+ type: "boolean",
41
+ defaultValue: false
42
+ },
43
+ triggerEventSync: {
44
+ label: "send trigger event to timeline Synchronously",
45
+ type: "boolean",
46
+ defaultValue: false
47
+ },
48
+ sendUpdate: {
49
+ label: "Record view update caused by model to timeline",
50
+ type: "boolean",
51
+ defaultValue: false
52
+ }
53
+ },
54
+ id: "dev.esm.phecda",
55
+ label: "Phecda Vue",
56
+ packageName: "phecda",
57
+ // @todo
58
+ // logo: 'https://phecda.vuejs.org/logo.svg',
59
+ // homepage: 'https://phecda.vuejs.org',
60
+ componentStateTypes,
61
+ app
62
+ }, (api) => {
63
+ const now = typeof api.now === "function" ? api.now.bind(api) : Date.now;
64
+ api.addTimelineLayer({
65
+ id: MUTATIONS_LAYER_ID,
66
+ label: "Phecda Vue",
67
+ color: 9089261
68
+ });
69
+ const watchModule = /* @__PURE__ */ __name((tag) => {
70
+ watch(this.get(tag), (data) => {
71
+ const { sendUpdate } = api.getSettings();
72
+ if (sendUpdate) {
73
+ api.addTimelineEvent({
74
+ layerId: MUTATIONS_LAYER_ID,
75
+ event: {
76
+ time: now(),
77
+ title: "Update",
78
+ subtitle: String(tag),
79
+ data: {
80
+ ...data
81
+ }
82
+ }
83
+ });
84
+ }
85
+ api.notifyComponentUpdate();
86
+ api.sendInspectorState(INSPECTOR_ID);
87
+ }, {
88
+ deep: true,
89
+ onTrigger(event) {
90
+ const { triggerEventSync, sendTrigger } = api.getSettings();
91
+ if (sendTrigger && !triggerEventSync) {
92
+ api.addTimelineEvent({
93
+ layerId: MUTATIONS_LAYER_ID,
94
+ event: {
95
+ time: now(),
96
+ title: "Trigger",
97
+ subtitle: String(tag),
98
+ data: event
99
+ }
100
+ });
101
+ }
102
+ }
103
+ });
104
+ watch(this.get(tag), () => {
105
+ }, {
106
+ deep: true,
107
+ flush: "sync",
108
+ onTrigger(event) {
109
+ const { triggerEventSync, sendTrigger } = api.getSettings();
110
+ if (sendTrigger && triggerEventSync) {
111
+ api.addTimelineEvent({
112
+ layerId: MUTATIONS_LAYER_ID,
113
+ event: {
114
+ time: now(),
115
+ title: "Trigger",
116
+ subtitle: String(tag),
117
+ data: event
118
+ }
119
+ });
120
+ }
121
+ }
122
+ });
123
+ }, "watchModule");
124
+ for (const tag in this.state) watchModule(tag);
125
+ this.on("Instantiate", ({ tag }) => {
126
+ api.sendInspectorTree(INSPECTOR_ID);
127
+ watchModule(tag);
128
+ });
129
+ this.on("*", (type, event) => {
130
+ api.addTimelineEvent({
131
+ layerId: MUTATIONS_LAYER_ID,
132
+ event: {
133
+ time: now(),
134
+ title: type,
135
+ subtitle: event.tag,
136
+ data: event
137
+ }
138
+ });
139
+ });
140
+ api.addInspector({
141
+ id: INSPECTOR_ID,
142
+ label: "Phecda Vue",
143
+ icon: "storage",
144
+ treeFilterPlaceholder: "Search",
145
+ actions: [
146
+ {
147
+ icon: "content_copy",
148
+ action: /* @__PURE__ */ __name(async () => {
149
+ toastMessage("Global state copied to clipboard.");
150
+ await navigator.clipboard.writeText(this.serialize());
151
+ }, "action"),
152
+ tooltip: "Serialize and copy the state"
153
+ },
154
+ {
155
+ icon: "content_paste",
156
+ action: /* @__PURE__ */ __name(async () => {
157
+ toastMessage("Global state pasted from clipboard.");
158
+ await this.load(await navigator.clipboard.readText());
159
+ api.sendInspectorTree(INSPECTOR_ID);
160
+ api.sendInspectorState(INSPECTOR_ID);
161
+ }, "action"),
162
+ tooltip: "Replace the state with the content of your clipboard"
163
+ }
164
+ ],
165
+ nodeActions: [
166
+ {
167
+ icon: "restore",
168
+ tooltip: "Reset the state ",
169
+ action: /* @__PURE__ */ __name((nodeId) => {
170
+ this.reset(this.getModel(nodeId));
171
+ }, "action")
172
+ }
173
+ ]
174
+ });
175
+ api.on.inspectComponent((payload) => {
176
+ const proxy = payload.componentInstance && payload.componentInstance.proxy;
177
+ if (proxy && proxy._phecda_vue) {
178
+ for (const tag in proxy._phecda_vue) {
179
+ payload.instanceData.state.push({
180
+ type: "phecda-vue",
181
+ key: tag,
182
+ editable: true,
183
+ value: proxy._phecda_vue[tag]
184
+ });
185
+ }
186
+ }
187
+ });
188
+ api.on.getInspectorTree((payload) => {
189
+ if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
190
+ payload.rootNodes = Object.keys(this.state).map((tag) => {
191
+ return {
192
+ id: tag,
193
+ label: tag
194
+ };
195
+ });
196
+ }
197
+ });
198
+ api.on.getInspectorState((payload) => {
199
+ if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
200
+ if (this.has(payload.nodeId)) {
201
+ const instance = this.get(payload.nodeId);
202
+ payload.state = {
203
+ state: [],
204
+ methods: [],
205
+ getters: [],
206
+ internals: [],
207
+ memory: Object.entries(this.memory[payload.nodeId] || {}).map(([key, value]) => {
208
+ return {
209
+ editable: false,
210
+ key,
211
+ value
212
+ };
213
+ })
214
+ };
215
+ Object.entries(instance).forEach(([key, value]) => {
216
+ if (this.modelMap.has(value)) {
217
+ const tag = String(getTag(toRaw(value)));
218
+ payload.state.state.unshift({
219
+ editable: false,
220
+ key,
221
+ value: `[PV] ${tag}`,
222
+ raw: `Phecda Vue Module [${tag}]`
223
+ });
224
+ return;
225
+ }
226
+ if (!key.startsWith("__")) payload.state.state.push({
227
+ editable: true,
228
+ key,
229
+ value
230
+ });
231
+ else payload.state.internals.push({
232
+ editable: false,
233
+ key,
234
+ value
235
+ });
236
+ });
237
+ getAllGetters(instance).forEach((item) => {
238
+ payload.state.getters.push({
239
+ editable: false,
240
+ key: item,
241
+ value: instance[item]
242
+ });
243
+ });
244
+ getAllMethods(instance).forEach((item) => {
245
+ if (typeof instance[item] === "function") payload.state[item.startsWith("__") ? "internals" : "methods"].push({
246
+ editable: false,
247
+ key: item,
248
+ value: Object.getPrototypeOf(instance)[item]
249
+ });
250
+ });
251
+ }
252
+ }
253
+ });
254
+ api.on.editInspectorState((payload) => {
255
+ if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
256
+ const state = this.get(payload.nodeId);
257
+ const { path } = payload;
258
+ payload.set(state, path, payload.state.value);
259
+ }
260
+ });
261
+ api.on.editComponentState((payload) => {
262
+ const { path, type } = payload;
263
+ if (type === "phecda-vue") payload.set(this.get(path.shift()), path, payload.state.value);
264
+ });
265
+ });
266
+ }
16
267
  }
17
268
  };
18
- __name(VuePhecda, "VuePhecda");
19
269
  function createPhecda() {
20
- return new VuePhecda((instance) => {
21
- return bindMethod(get(instance, "shallow") ? shallowReactive(instance) : reactive(instance));
270
+ const phecda = new VuePhecda("vue", (instance) => {
271
+ return bindMethod(get(instance, "shallow") ? shallowReactive(instance) : reactive(instance), USE_DEVTOOLS ? (instance2, key) => {
272
+ const cb = instance2[key].bind(instance2);
273
+ if (findPrototypeWithMethod(instance2, key).constructor.name === "Object") return cb;
274
+ const tag = getTag(instance2);
275
+ return (...args) => {
276
+ const name = `${tag}.${key}`;
277
+ phecda.emit(`Invoke ${name}`, {
278
+ args,
279
+ tag,
280
+ key
281
+ });
282
+ const ret = cb(...args);
283
+ if (ret instanceof Promise) ret.then(() => phecda.emit(`End ${name}(Async)`, {
284
+ args,
285
+ tag,
286
+ key
287
+ }));
288
+ else phecda.emit(`End ${name}`, {
289
+ args,
290
+ tag,
291
+ key
292
+ });
293
+ return ret;
294
+ };
295
+ } : void 0);
22
296
  });
297
+ return phecda;
23
298
  }
24
299
  __name(createPhecda, "createPhecda");
300
+ function findPrototypeWithMethod(instance, method) {
301
+ let proto = Object.getPrototypeOf(instance);
302
+ while (proto) {
303
+ if (proto.hasOwnProperty(method)) return proto;
304
+ proto = Object.getPrototypeOf(proto);
305
+ }
306
+ return null;
307
+ }
308
+ __name(findPrototypeWithMethod, "findPrototypeWithMethod");
309
+ function getAllMethods(obj) {
310
+ const methods = /* @__PURE__ */ new Set();
311
+ obj = Object.getPrototypeOf(obj);
312
+ while (obj.constructor.name !== "Object") {
313
+ Object.getOwnPropertyNames(obj).forEach((prop) => {
314
+ const propDescriptor = Object.getOwnPropertyDescriptor(obj, prop);
315
+ if (typeof propDescriptor.value === "function" && prop !== "constructor") methods.add(prop);
316
+ });
317
+ obj = Object.getPrototypeOf(obj);
318
+ }
319
+ return [
320
+ ...methods
321
+ ];
322
+ }
323
+ __name(getAllMethods, "getAllMethods");
324
+ function getAllGetters(obj) {
325
+ const getters = /* @__PURE__ */ new Set();
326
+ obj = Object.getPrototypeOf(obj);
327
+ while (obj.constructor.name !== "Object") {
328
+ Object.getOwnPropertyNames(obj).forEach((prop) => {
329
+ const propDescriptor = Object.getOwnPropertyDescriptor(obj, prop);
330
+ if (typeof propDescriptor.get === "function") getters.add(prop);
331
+ });
332
+ obj = Object.getPrototypeOf(obj);
333
+ }
334
+ return [
335
+ ...getters
336
+ ];
337
+ }
338
+ __name(getAllGetters, "getAllGetters");
25
339
 
26
340
  // src/composable.ts
27
- import { bindMethod as bindMethod2, emitter, getDefaultPhecda } from "phecda-web";
28
- import { hasInjectionContext, inject, onBeforeUnmount, toRaw, toRef } from "vue";
341
+ import { bindMethod as bindMethod2, emitter, getDefaultPhecda, getTag as getTag2 } from "phecda-web";
342
+ import { getCurrentInstance, hasInjectionContext, inject, onBeforeUnmount, toRaw as toRaw2, toRef } from "vue";
29
343
 
30
344
  // src/utils.ts
31
345
  import { effectScope, onScopeDispose, markRaw as raw } from "vue";
@@ -60,26 +374,33 @@ __name(createSharedReactive, "createSharedReactive");
60
374
  // src/composable.ts
61
375
  var cacheMap = /* @__PURE__ */ new WeakMap();
62
376
  function useRaw(model) {
63
- return toRaw(useR(model));
377
+ return toRaw2(useR(model));
64
378
  }
65
379
  __name(useRaw, "useRaw");
66
380
  function usePhecda() {
67
- if (!hasInjectionContext())
68
- throw new Error("[phecda-vue]: use hook inside component setup function");
381
+ if (!hasInjectionContext()) throw new Error("[phecda-vue]: use hook inside component setup function");
69
382
  const activePhecda = inject(phecdaSymbol);
70
- if (!activePhecda)
71
- throw new Error("[phecda-vue]: must install the vue plugin ");
72
- if (!cacheMap.has(activePhecda))
73
- cacheMap.set(activePhecda, bindMethod2(activePhecda));
383
+ if (!activePhecda) throw new Error("[phecda-vue]: must install the vue plugin ");
384
+ if (!cacheMap.has(activePhecda)) cacheMap.set(activePhecda, bindMethod2(activePhecda));
74
385
  return cacheMap.get(activePhecda);
75
386
  }
76
387
  __name(usePhecda, "usePhecda");
388
+ function setStateToComponent(model) {
389
+ if (USE_DEVTOOLS) {
390
+ const currentInstance = getCurrentInstance();
391
+ if (currentInstance && currentInstance.proxy) {
392
+ const vm = currentInstance.proxy;
393
+ const cache = "_phecda_vue" in vm ? vm._phecda_vue : vm._phecda_vue = {};
394
+ const tag = getTag2(model);
395
+ cache[tag] = usePhecda().init(model);
396
+ }
397
+ }
398
+ }
399
+ __name(setStateToComponent, "setStateToComponent");
77
400
  function getPhecda(phecda) {
78
- const activePhecda = phecda || getDefaultPhecda();
79
- if (!activePhecda)
80
- throw new Error("[phecda-vue]: manually inject the phecda instance if there is no default phecda");
81
- if (!cacheMap.has(activePhecda))
82
- cacheMap.set(activePhecda, bindMethod2(activePhecda));
401
+ const activePhecda = phecda || getDefaultPhecda("vue");
402
+ if (!activePhecda) throw new Error("[phecda-vue]: manually inject the phecda instance if there is no default phecda");
403
+ if (!cacheMap.has(activePhecda)) cacheMap.set(activePhecda, bindMethod2(activePhecda));
83
404
  return cacheMap.get(activePhecda);
84
405
  }
85
406
  __name(getPhecda, "getPhecda");
@@ -89,12 +410,13 @@ function useEvent(eventName, cb) {
89
410
  });
90
411
  emitter.on(eventName, cb);
91
412
  return {
92
- emit: (arg) => emitter.emit(eventName, arg),
93
- cancel: () => emitter.off(eventName, cb)
413
+ emit: /* @__PURE__ */ __name((arg) => emitter.emit(eventName, arg), "emit"),
414
+ cancel: /* @__PURE__ */ __name(() => emitter.off(eventName, cb), "cancel")
94
415
  };
95
416
  }
96
417
  __name(useEvent, "useEvent");
97
418
  function useR(model) {
419
+ setStateToComponent(model);
98
420
  return usePhecda().init(model);
99
421
  }
100
422
  __name(useR, "useR");
@@ -103,19 +425,16 @@ function getR(model, phecda) {
103
425
  }
104
426
  __name(getR, "getR");
105
427
  function useV(model) {
428
+ setStateToComponent(model);
106
429
  const instance = usePhecda().init(model);
107
- if (cacheMap.has(instance))
108
- return cacheMap.get(instance);
430
+ if (cacheMap.has(instance)) return cacheMap.get(instance);
109
431
  const cache = {};
110
432
  const proxy = new Proxy(instance, {
111
433
  get(target, key) {
112
- if (typeof target[key] === "function")
113
- return target[key];
114
- if (target[key]?.__v_skip)
115
- return target[key];
434
+ if (typeof target[key] === "function") return target[key];
435
+ if (target[key]?.__v_skip) return target[key];
116
436
  const cacheRef = cache[key];
117
- if (cacheRef && cacheRef.r)
118
- return cacheRef();
437
+ if (cacheRef && cacheRef.r) return cacheRef();
119
438
  cache[key] = createSharedReactive(() => {
120
439
  return toRef(target, key);
121
440
  });
@@ -131,18 +450,14 @@ function useV(model) {
131
450
  __name(useV, "useV");
132
451
  function getV(model, phecda) {
133
452
  const instance = getPhecda(phecda).init(model);
134
- if (cacheMap.has(instance))
135
- return cacheMap.get(instance);
453
+ if (cacheMap.has(instance)) return cacheMap.get(instance);
136
454
  const cache = {};
137
455
  const proxy = new Proxy(instance, {
138
456
  get(target, key) {
139
- if (typeof target[key] === "function")
140
- return target[key];
141
- if (target[key]?.__v_skip)
142
- return target[key];
457
+ if (typeof target[key] === "function") return target[key];
458
+ if (target[key]?.__v_skip) return target[key];
143
459
  const cacheRef = cache[key];
144
- if (cacheRef && cacheRef.r)
145
- return cacheRef();
460
+ if (cacheRef && cacheRef.r) return cacheRef();
146
461
  cache[key] = createSharedReactive(() => {
147
462
  return toRef(target, key);
148
463
  });
@@ -160,10 +475,8 @@ __name(getV, "getV");
160
475
  // src/decorator.ts
161
476
  import { set, setHandler, setStateKey } from "phecda-web";
162
477
  import { watchEffect } from "vue";
163
- function Shallow(isShallow = true) {
164
- return (model) => {
165
- set(model.prototype, "shallow", isShallow);
166
- };
478
+ function Shallow(model) {
479
+ set(model.prototype, "shallow", true);
167
480
  }
168
481
  __name(Shallow, "Shallow");
169
482
  function WatchEffect(option) {
@@ -172,8 +485,7 @@ function WatchEffect(option) {
172
485
  let stopHandler;
173
486
  setHandler(proto, key, {
174
487
  init(instance) {
175
- if (typeof instance[key] !== "function")
176
- throw new Error("WatchEffect must decorate function");
488
+ if (typeof instance[key] !== "function") throw new Error("WatchEffect must decorate function");
177
489
  stopHandler = watchEffect(instance[key].bind(instance), option);
178
490
  },
179
491
  unmount() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phecda-vue",
3
- "version": "4.0.2",
3
+ "version": "4.0.4",
4
4
  "description": "provide phecda function to vue",
5
5
  "author": "fgsreally",
6
6
  "license": "MIT",
@@ -16,12 +16,13 @@
16
16
  "dist"
17
17
  ],
18
18
  "dependencies": {
19
+ "@vue/devtools-api": "^6.6.3",
19
20
  "vue": "^3.2.45",
20
- "phecda-web": "2.0.2"
21
+ "phecda-web": "2.0.4"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@vue/test-utils": "^2.4.6",
24
- "tsup": "^6.5.0"
25
+ "tsup": "^8.1.0"
25
26
  },
26
27
  "scripts": {
27
28
  "build": "tsup",