@arrai-innovations/reactive-helpers 5.0.1 → 6.1.0

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,3 @@
1
+ {
2
+ "recommendations": ["Vue.volar", "dbaeumer.vscode-eslint"]
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrai-innovations/reactive-helpers",
3
- "version": "5.0.1",
3
+ "version": "6.1.0",
4
4
  "description": "VueJS 3 utility composition functions to help manipulate objects and lists.",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -1,8 +1,11 @@
1
+ import { useDebugMessage } from "../utils";
1
2
  import identity from "lodash-es/identity";
2
3
  import isEqual from "lodash-es/isEqual";
3
4
  import { effectScope, nextTick, onScopeDispose, reactive, readonly, watch } from "vue";
4
5
  import { deepUnref } from "vue-deepunref";
5
6
 
7
+ const watchFnDebugMessage = useDebugMessage(["cancellableIntent", "watch"]);
8
+
6
9
  /*
7
10
  * Calls your awaitable function with the arguments you pass in, when the watch arguments change and are all truthy.
8
11
  * Watch arguments should be a reactive object.
@@ -44,6 +47,7 @@ export function useCancellableIntent({ awaitableWithCancel, watchArguments = {},
44
47
  }
45
48
 
46
49
  const watchFn = () => {
50
+ watchFnDebugMessage("watchFn called");
47
51
  let newWatchValues = deepUnref(Object.values(watchArguments));
48
52
  if (isEqual(newWatchValues, previousWatchValues)) {
49
53
  return;
package/use/list.js CHANGED
@@ -3,116 +3,49 @@ import { useListInstance } from "./listInstance";
3
3
  import { useListRelated } from "./listRelated";
4
4
  import { useListSubscription } from "./listSubscription";
5
5
  import { usePagedListInstance } from "./paginatedListInstance";
6
- import { effectScope, reactive, shallowReactive, shallowReadonly, toRef, watch } from "vue";
6
+ import { reactive, shallowReactive, shallowReadonly, toRef } from "vue";
7
+
8
+ export const useLists = (listArgs) => {
9
+ const lists = {};
10
+ for (const [key, value] of Object.entries(listArgs)) {
11
+ lists[key] = useList(value);
12
+ }
13
+ return lists;
14
+ };
7
15
 
8
16
  // the big brother of useObject, managing a chain of useList* instances.
9
- export const useList = ({ props, functions, paged = false, keepOldPages = false, passThroughPropertyNames = [] }) => {
17
+ export const useList = ({ props, functions, paged = false, keepOldPages = false }) => {
10
18
  const managed = shallowReactive({
11
19
  listInstance: null,
12
20
  listSubscription: null,
13
21
  listRelated: null,
14
22
  listCalculated: null,
15
23
  });
16
- const es = effectScope();
17
24
 
18
25
  managed.listInstance = (paged ? usePagedListInstance : useListInstance)({
19
- crudArgs: toRef(props, "crudArgs"),
26
+ props,
20
27
  functions,
21
- retrieveArgs: toRef(props, "retrieveArgs"),
22
- listArgs: toRef(props, "listArgs"),
23
28
  keepOldPages,
24
29
  });
25
30
 
26
- const intentPropsWatch = () => {
27
- es.run(() => {
28
- let nextState = managed.listInstance?.state;
29
- // true or false, having a key is intent to use
30
- const hasIntendToList = "intendToList" in props;
31
- if (hasIntendToList && !managed.listSubscription) {
32
- managed.listSubscription = useListSubscription({
33
- listInstance: managed.listInstance,
34
- });
35
- managed.listSubscription.state.intendToList = toRef(props, "intendToList");
36
- } else if (!hasIntendToList && managed.listSubscription) {
37
- managed.listSubscription.effectScope.stop();
38
- managed.listSubscription = null;
39
- }
40
- const hasRelatedObjectRules = "relatedObjectsRules" in props;
41
- if (hasRelatedObjectRules && !managed.listRelated) {
42
- nextState = managed.listSubscription?.state || nextState;
43
- managed.listRelated = useListRelated({
44
- parentState: nextState,
45
- relatedObjectsRules: toRef(props, "relatedObjectsRules"),
46
- });
47
- } else if (!hasRelatedObjectRules && managed.listRelated) {
48
- managed.listRelated.effectScope.stop();
49
- managed.listRelated = null;
50
- }
51
- const hasCalculatedObjectRules = "calculatedObjectsRules" in props;
52
- if (hasCalculatedObjectRules && !managed.listCalculated) {
53
- nextState = managed.listRelated?.state || nextState;
54
- managed.listCalculated = useListCalculated({
55
- parentState: nextState,
56
- calculatedObjectsRules: toRef(props, "calculatedObjectsRules"),
57
- });
58
- } else if (!hasCalculatedObjectRules && managed.listCalculated) {
59
- managed.listCalculated.effectScope.stop();
60
- managed.listCalculated = null;
61
- }
62
- });
63
- };
31
+ managed.listSubscription = useListSubscription({
32
+ listInstance: managed.listInstance,
33
+ });
34
+ managed.listSubscription.state.intendToList = toRef(props, "intendToList");
64
35
 
65
- const exposedState = reactive({});
36
+ managed.listRelated = useListRelated({
37
+ parentState: managed.listSubscription.state,
38
+ relatedObjectsRules: toRef(props, "relatedObjectsRules"),
39
+ });
66
40
 
67
- es.run(() => {
68
- watch(
69
- [
70
- //
71
- toRef(props, "intendToList"),
72
- toRef(props, "relatedObjectsRules"),
73
- toRef(props, "calculatedObjectsRules"),
74
- ],
75
- intentPropsWatch,
76
- { immediate: true }
77
- );
78
- const propertiesToRelay = [
79
- "loading",
80
- "error",
81
- "errored",
82
- "objects",
83
- "order",
84
- "objectsInOrder",
85
- "running",
86
- "relatedObjects",
87
- "calculatedObjects",
88
- "totalRecords",
89
- "totalPages",
90
- "perPage",
91
- ...passThroughPropertyNames,
92
- ];
93
- watch(
94
- () =>
95
- managed.listCalculated?.state ||
96
- managed.listRelated?.state ||
97
- managed.listSubscription?.state ||
98
- managed.listInstance?.state,
99
- (newState, oldState) => {
100
- if (newState !== oldState && newState) {
101
- propertiesToRelay.forEach((x) => {
102
- exposedState[x] = toRef(newState, x);
103
- });
104
- }
105
- },
106
- {
107
- immediate: true,
108
- }
109
- );
41
+ managed.listCalculated = useListCalculated({
42
+ parentState: managed.listRelated.state,
43
+ calculatedObjectsRules: toRef(props, "calculatedObjectsRules"),
110
44
  });
111
45
 
112
- return {
46
+ return reactive({
113
47
  // we manage the keys on both of these, so hands off the root.
114
48
  managed: shallowReadonly(managed),
115
- state: shallowReadonly(exposedState),
116
- effectScope: es,
117
- };
49
+ state: managed.listCalculated.state,
50
+ });
118
51
  };
@@ -1,8 +1,21 @@
1
- import { keyDiff, loadingCombine } from "../utils";
1
+ import { keyDiff, loadingCombine, useDebugMessage } from "../utils";
2
+ import { listInstanceStateKeys } from "./listInstance";
3
+ import { listRelatedStateKeys } from "./listRelated";
4
+ import { listSubscriptionStateKeys } from "./listSubscription";
2
5
  import { useWatchesRunning } from "./watchesRunning";
3
6
  import isEmpty from "lodash-es/isEmpty";
4
7
  import { computed, effectScope, onScopeDispose, reactive, toRef, watch } from "vue";
5
8
 
9
+ const computedDebugMessage = useDebugMessage(["listCalculated", "computed"]);
10
+ const watchDebugMessage = useDebugMessage(["listCalculated", "watch"]);
11
+
12
+ export const listCalculatedStateKeys = [
13
+ "calculatedObjects",
14
+ "calculatedObjectsParentStateObjectsWatchRunning",
15
+ "calculatedObjectsRules",
16
+ "calculatedObjectsWatchRunning",
17
+ ];
18
+
6
19
  export function useListCalculateds(instances, args) {
7
20
  for (const [key, value] of Object.entries(args)) {
8
21
  useListCalculated({
@@ -15,52 +28,46 @@ export function useListCalculateds(instances, args) {
15
28
  // the simpler sibling of useListRelated
16
29
  // rules are just keys to functions that will be called with the object
17
30
  // and the result will be added as a computed property
18
- export function useListCalculated({
19
- parentState,
20
- calculatedObjectsRules,
21
- calculatedObjectsPropertyName = "calculatedObjects", // NOT REACTIVE
22
- passThroughPropertyNames = ["relatedObjects", "totalRecords", "totalPages", "perPage"], // NOT REACTIVE
23
- }) {
31
+ export function useListCalculated({ parentState, calculatedObjectsRules }) {
24
32
  const state = reactive({
25
33
  calculatedObjectsRules,
26
- calculatedObjectsObjects: {},
27
- parentStateObjectsWatchRunning: false,
34
+ calculatedObjects: {},
35
+ calculatedObjectsParentStateObjectsWatchRunning: false,
28
36
  calculatedObjectsWatchRunning: false,
29
37
  });
30
38
  const calculatedObjectsEffectScopes = {};
31
39
 
32
- // don't change calculatedObjectsPropertyName on us or it will break
33
- const copn = calculatedObjectsPropertyName + "";
34
-
35
40
  function parentStateObjectsWatch() {
41
+ watchDebugMessage("parentStateObjectsWatch called");
36
42
  const { addedKeys, removedKeys } = keyDiff(
37
43
  Object.keys(parentState.objects),
38
- Object.keys(state.calculatedObjectsObjects)
44
+ Object.keys(state.calculatedObjects)
39
45
  );
40
46
  for (const removedKey of removedKeys) {
41
- delete state.calculatedObjectsObjects[removedKey];
47
+ delete state.calculatedObjects[removedKey];
42
48
  if (calculatedObjectsEffectScopes[removedKey]) {
43
49
  calculatedObjectsEffectScopes[removedKey].stop();
44
50
  delete calculatedObjectsEffectScopes[removedKey];
45
51
  }
46
52
  }
47
53
  for (const addedKey of addedKeys) {
48
- state.calculatedObjectsObjects[addedKey] = {};
54
+ state.calculatedObjects[addedKey] = {};
49
55
  }
50
- state.parentStateObjectsWatchRunning = false;
56
+ state.calculatedObjectsParentStateObjectsWatchRunning = false;
51
57
  }
52
58
 
53
59
  function calculatedObjectsWatch() {
60
+ watchDebugMessage("calculatedObjectsWatch called");
54
61
  const calculatedObjectsRulesIsEmpty = !state.calculatedObjectsRules || isEmpty(state.calculatedObjectsRules);
55
- for (const objectKey of Object.keys(state.calculatedObjectsObjects)) {
62
+ for (const objectKey of Object.keys(state.calculatedObjects)) {
56
63
  if (!calculatedObjectsEffectScopes[objectKey]) {
57
64
  calculatedObjectsEffectScopes[objectKey] = effectScope();
58
65
  }
59
66
  const originalObject = parentState.objects[objectKey];
60
- if (!state.calculatedObjectsObjects[objectKey]) {
61
- state.calculatedObjectsObjects[objectKey] = {};
67
+ if (!state.calculatedObjects[objectKey]) {
68
+ state.calculatedObjects[objectKey] = {};
62
69
  }
63
- const calculatedObjectsObject = state.calculatedObjectsObjects[objectKey];
70
+ const calculatedObjectsObject = state.calculatedObjects[objectKey];
64
71
  let removedRuleKeys, addedRuleKeys;
65
72
  if (!calculatedObjectsRulesIsEmpty) {
66
73
  ({ removedKeys: removedRuleKeys, addedKeys: addedRuleKeys } = keyDiff(
@@ -93,24 +100,20 @@ export function useListCalculated({
93
100
  const es = effectScope();
94
101
 
95
102
  es.run(() => {
96
- state.loading = toRef(parentState, "loading");
97
- state.errored = toRef(parentState, "errored");
98
- state.error = toRef(parentState, "error");
99
-
100
- state.retrieveArgs = toRef(parentState, "retrieveArgs");
101
- state.listArgs = toRef(parentState, "listArgs");
102
- state.order = toRef(parentState, "order");
103
- state.objects = toRef(parentState, "objects");
104
- state.objectsInOrder = toRef(parentState, "objectsInOrder");
105
- state[copn] = toRef(state, "calculatedObjectsObjects");
106
- for (let key of passThroughPropertyNames) {
103
+ for (const key of listInstanceStateKeys) {
104
+ state[key] = toRef(parentState, key);
105
+ }
106
+ for (const key of listSubscriptionStateKeys) {
107
+ state[key] = toRef(parentState, key);
108
+ }
109
+ for (const key of listRelatedStateKeys) {
107
110
  state[key] = toRef(parentState, key);
108
111
  }
109
112
 
110
113
  watch(() => Object.keys(parentState.objects), parentStateObjectsWatch, { immediate: true });
111
114
  watch(
112
115
  [
113
- () => Object.keys(state.calculatedObjectsObjects),
116
+ () => Object.keys(state.calculatedObjects),
114
117
  () =>
115
118
  state.calculatedObjectsRules
116
119
  ? Object.keys(state.calculatedObjectsRules)
@@ -122,17 +125,23 @@ export function useListCalculated({
122
125
 
123
126
  watchesRunning = useWatchesRunning({
124
127
  triggerRefs: [
125
- computed(() =>
126
- state.calculatedObjectsRules && !isEmpty(state.calculatedObjectsRules) ? parentState.loading : false
127
- ),
128
+ computed(() => {
129
+ computedDebugMessage("listCalculated trigger");
130
+ return state.calculatedObjectsRules && !isEmpty(state.calculatedObjectsRules)
131
+ ? parentState.loading
132
+ : false;
133
+ }),
128
134
  ],
129
135
  watchSentinelRefs: [
130
- toRef(state, "parentStateObjectsWatchRunning"),
136
+ toRef(state, "calculatedObjectsParentStateObjectsWatchRunning"),
131
137
  toRef(state, "calculatedObjectsWatchRunning"),
132
138
  ],
133
139
  });
134
140
 
135
- state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
141
+ state.running = computed(() => {
142
+ computedDebugMessage("listCalculated running");
143
+ return loadingCombine(watchesRunning.state.running, parentState.running);
144
+ });
136
145
 
137
146
  onScopeDispose(() => {
138
147
  for (const objectKey of Object.keys(calculatedObjectsEffectScopes)) {
@@ -3,7 +3,7 @@ import { getFakeId } from "../utils/getFakeId";
3
3
  import inspect from "browser-util-inspect";
4
4
  import cloneDeep from "lodash-es/cloneDeep";
5
5
  import isFunction from "lodash-es/isFunction";
6
- import { computed, effectScope, reactive } from "vue";
6
+ import { computed, effectScope, reactive, toRef, watchEffect } from "vue";
7
7
 
8
8
  export class ListError extends Error {
9
9
  constructor(message, code) {
@@ -18,6 +18,22 @@ const defaultCrud = {
18
18
  list: undefined,
19
19
  };
20
20
 
21
+ export const listInstanceStateKeys = [
22
+ "crud",
23
+ "retrieveArgs",
24
+ "listArgs",
25
+ "objects",
26
+ "loading",
27
+ "errored",
28
+ "error",
29
+ "objectsInOrder",
30
+ "order",
31
+ // when paged
32
+ "totalRecords",
33
+ "totalPages",
34
+ "perPage",
35
+ ];
36
+
21
37
  export function setListInstanceCrud({ list, args = {} } = {}) {
22
38
  defaultCrud.list = list;
23
39
  Object.assign(defaultCrud.args, args);
@@ -31,7 +47,10 @@ export function useListInstances(listInstanceArgs) {
31
47
  return instances;
32
48
  }
33
49
 
34
- export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {}, functions = {} }) {
50
+ export function useListInstance({ props, functions = {} }) {
51
+ if (!props) {
52
+ throw new ListError(`useListInstance requires props`);
53
+ }
35
54
  // ### touching the _objectsMap or _objectsProxy directly will not trigger reactivity ###
36
55
  const _objectsMap = new Map(); // maps are ordered, if you don't clear lists, you need to insert pages in order.
37
56
  // ### touching the _objectsMap or _objectsProxy directly will not trigger reactivity ###
@@ -71,25 +90,28 @@ export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {}, fu
71
90
  args: {},
72
91
  list: undefined,
73
92
  },
74
- retrieveArgs,
75
- listArgs,
93
+ retrieveArgs: toRef(props, "retrieveArgs"),
94
+ listArgs: toRef(props, "listArgs"),
76
95
  objects: _objectsProxy,
77
96
  loading: undefined,
78
97
  errored: false,
79
98
  error: null,
80
99
  });
81
- // prevent linking of all instances to the same default .args object
82
- Object.assign(state.crud, cloneDeep(defaultCrud));
83
- if (crudArgs) {
84
- addOrUpdateReactiveObject(state.crud.args, crudArgs);
85
- }
86
- for (const [key, value] of Object.entries(functions)) {
87
- if (isFunction(value) && key in state.crud) {
88
- state.crud[key] = value;
89
- } else {
90
- throw ListError(`Invalid function "${key}" for useListInstance: invalid key or not a function.`);
100
+ const es = effectScope();
101
+ watchEffect(() => {
102
+ // prevent linking of all instances to the same default .args object
103
+ Object.assign(state.crud, cloneDeep(defaultCrud));
104
+ if (props.crudArgs) {
105
+ addOrUpdateReactiveObject(state.crud.args, props.crudArgs);
91
106
  }
92
- }
107
+ for (const [key, value] of Object.entries(functions)) {
108
+ if (isFunction(value) && key in state.crud) {
109
+ state.crud[key] = value;
110
+ } else {
111
+ throw ListError(`Invalid function "${key}" for useListInstance: invalid key or not a function.`);
112
+ }
113
+ }
114
+ });
93
115
 
94
116
  const defaultPageCallback = (newObjects) => {
95
117
  newObjects.forEach((newObject) => {
@@ -191,12 +213,8 @@ export function useListInstance({ crudArgs, listArgs = {}, retrieveArgs = {}, fu
191
213
  state.error = null;
192
214
  }
193
215
 
194
- const es = effectScope();
195
-
196
- es.run(() => {
197
- state.objectsInOrder = computed(() => Object.values(state.objects));
198
- state.order = computed(() => Object.keys(state.objects));
199
- });
216
+ state.objectsInOrder = computed(() => Object.values(state.objects));
217
+ state.order = computed(() => Object.keys(state.objects));
200
218
 
201
219
  const returnedObject = {
202
220
  state,
@@ -1,4 +1,6 @@
1
- import { keyDiff, loadingCombine } from "../utils";
1
+ import { keyDiff, loadingCombine, useDebugMessage } from "../utils";
2
+ import { listInstanceStateKeys } from "./listInstance";
3
+ import { listSubscriptionStateKeys } from "./listSubscription";
2
4
  import { useWatchesRunning } from "./watchesRunning";
3
5
  import get from "lodash-es/get";
4
6
  import isArray from "lodash-es/isArray";
@@ -6,6 +8,16 @@ import isEmpty from "lodash-es/isEmpty";
6
8
  import isUndefined from "lodash-es/isUndefined";
7
9
  import { computed, effectScope, onScopeDispose, reactive, toRef, unref, watch } from "vue";
8
10
 
11
+ const computedDebugMessage = useDebugMessage(["listRelated", "computed"]);
12
+ const watchDebugMessage = useDebugMessage(["listRelated", "watch"]);
13
+
14
+ export const listRelatedStateKeys = [
15
+ "relatedObjects",
16
+ "relatedObjectsRules",
17
+ "relatedObjectsWatchRunning",
18
+ "relatedObjectsParentStateObjectsWatchRunning",
19
+ ];
20
+
9
21
  export function useListRelateds(instances, args) {
10
22
  for (const [key, value] of Object.entries(args)) {
11
23
  useListRelated({
@@ -15,45 +27,36 @@ export function useListRelateds(instances, args) {
15
27
  }
16
28
  }
17
29
 
18
- export function useListRelated({
19
- parentState,
20
- relatedObjectsRules,
21
- relatedObjectsPropertyName = "relatedObjects", // NOT REACTIVE
22
- passThroughPropertyNames = ["calculatedObjects", "totalRecords", "totalPages", "perPage"], // NOT REACTIVE
23
- }) {
30
+ export function useListRelated({ parentState, relatedObjectsRules }) {
24
31
  const state = reactive({
25
32
  relatedObjectsRules: relatedObjectsRules,
26
- relatedObjectsObjects: {},
27
- parentStateObjectsWatchRunning: false,
33
+ relatedObjects: {},
34
+ relatedObjectsParentStateObjectsWatchRunning: false,
28
35
  relatedObjectsWatchRunning: false,
29
36
  });
30
37
  const relatedObjectsEffectScopes = {};
31
38
 
32
- // don't change relatedObjectsPropertyName on us or it will break
33
- const ropn = relatedObjectsPropertyName + "";
34
-
35
39
  function parentStateObjectsWatch() {
36
- const { addedKeys, removedKeys } = keyDiff(
37
- Object.keys(parentState.objects),
38
- Object.keys(state.relatedObjectsObjects)
39
- );
40
+ watchDebugMessage("parentStateObjectsWatch called");
41
+ const { addedKeys, removedKeys } = keyDiff(Object.keys(parentState.objects), Object.keys(state.relatedObjects));
40
42
  for (const removedKey of removedKeys) {
41
- delete state.relatedObjectsObjects[removedKey];
43
+ delete state.relatedObjects[removedKey];
42
44
  if (relatedObjectsEffectScopes[removedKey]) {
43
45
  relatedObjectsEffectScopes[removedKey].stop();
44
46
  delete relatedObjectsEffectScopes[removedKey];
45
47
  }
46
48
  }
47
49
  for (const addedKey of addedKeys) {
48
- state.relatedObjectsObjects[addedKey] = {};
50
+ state.relatedObjects[addedKey] = {};
49
51
  }
50
- state.parentStateObjectsWatchRunning = false;
52
+ state.relatedObjectsParentStateObjectsWatchRunning = false;
51
53
  }
52
54
 
53
55
  function relatedObjectsWatch() {
56
+ watchDebugMessage("relatedObjectsWatch called");
54
57
  const relatedObjectsRulesIsEmpty = !state.relatedObjectsRules || isEmpty(state.relatedObjectsRules);
55
- for (const objectKey of Object.keys(state.relatedObjectsObjects)) {
56
- const relatedObjectsObject = state.relatedObjectsObjects[objectKey];
58
+ for (const objectKey of Object.keys(state.relatedObjects)) {
59
+ const relatedObjectsObject = state.relatedObjects[objectKey];
57
60
  const originalObject = parentState.objects[objectKey];
58
61
  let removedRuleKeys, addedRuleKeys;
59
62
  if (!relatedObjectsRulesIsEmpty) {
@@ -103,24 +106,17 @@ export function useListRelated({
103
106
  const es = effectScope();
104
107
 
105
108
  es.run(() => {
106
- state.loading = toRef(parentState, "loading");
107
- state.errored = toRef(parentState, "errored");
108
- state.error = toRef(parentState, "error");
109
-
110
- state.retrieveArgs = toRef(parentState, "retrieveArgs");
111
- state.listArgs = toRef(parentState, "listArgs");
112
- state.order = toRef(parentState, "order");
113
- state.objects = toRef(parentState, "objects");
114
- state.objectsInOrder = toRef(parentState, "objectsInOrder");
115
- state[ropn] = toRef(state, "relatedObjectsObjects");
116
- for (let key of passThroughPropertyNames) {
109
+ for (const key of listInstanceStateKeys) {
110
+ state[key] = toRef(parentState, key);
111
+ }
112
+ for (const key of listSubscriptionStateKeys) {
117
113
  state[key] = toRef(parentState, key);
118
114
  }
119
115
 
120
116
  watch(() => Object.keys(parentState.objects), parentStateObjectsWatch, { immediate: true });
121
117
  watch(
122
118
  [
123
- () => Object.keys(state.relatedObjectsObjects),
119
+ () => Object.keys(state.relatedObjects),
124
120
  () => (state.relatedObjectsRules ? Object.keys(state.relatedObjectsRules) : state.relatedObjectsRules),
125
121
  ],
126
122
  relatedObjectsWatch,
@@ -129,17 +125,23 @@ export function useListRelated({
129
125
 
130
126
  watchesRunning = useWatchesRunning({
131
127
  triggerRefs: [
132
- computed(() =>
133
- state.relatedObjectsRules && !isEmpty(state.relatedObjectsRules) ? parentState.loading : false
134
- ),
128
+ computed(() => {
129
+ computedDebugMessage("listRelated triggerRefs");
130
+ return state.relatedObjectsRules && !isEmpty(state.relatedObjectsRules)
131
+ ? parentState.loading
132
+ : false;
133
+ }),
135
134
  ],
136
135
  watchSentinelRefs: [
137
- toRef(state, "parentStateObjectsWatchRunning"),
136
+ toRef(state, "relatedObjectsParentStateObjectsWatchRunning"),
138
137
  toRef(state, "relatedObjectsWatchRunning"),
139
138
  ],
140
139
  });
141
140
 
142
- state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.running));
141
+ state.running = computed(() => {
142
+ computedDebugMessage("listRelated running");
143
+ return loadingCombine(watchesRunning.state.running, parentState.running);
144
+ });
143
145
 
144
146
  onScopeDispose(() => {
145
147
  for (const objectKey of Object.keys(relatedObjectsEffectScopes)) {
@@ -1,6 +1,6 @@
1
1
  import { loadingCombine } from "../utils/loadingCombine";
2
2
  import { useCancellableIntent } from "./cancellableIntent";
3
- import { useListInstance } from "./listInstance";
3
+ import { listInstanceStateKeys, useListInstance } from "./listInstance";
4
4
  import inspect from "browser-util-inspect";
5
5
  import cloneDeep from "lodash-es/cloneDeep";
6
6
  import isEmpty from "lodash-es/isEmpty";
@@ -18,6 +18,15 @@ const defaultCrud = {
18
18
  subscribe: undefined,
19
19
  };
20
20
 
21
+ export const listSubscriptionStateKeys = [
22
+ "subscriptionLoading",
23
+ "subscriptionErrored",
24
+ "subscriptionError",
25
+ "intendToList",
26
+ "intendToSubscribe",
27
+ "subscribed",
28
+ ];
29
+
21
30
  export function setListSubscriptionCrud({ subscribe }) {
22
31
  defaultCrud.subscribe = subscribe;
23
32
  }
@@ -30,15 +39,17 @@ export function useListSubscriptions(args, listInstances = {}) {
30
39
  return subscriptions;
31
40
  }
32
41
 
33
- export function useListSubscription({
34
- listInstance,
35
- crudArgs,
36
- listArgs,
37
- retrieveArgs,
38
- passThroughPropertyNames = ["totalRecords", "totalPages", "perPage"],
39
- }) {
42
+ export function useListSubscription({ listInstance, props, functions }) {
43
+ if (!listInstance && !props) {
44
+ throw new ListSubscriptionError("useListSubscription should be passed listInstance or props and crudArgs.");
45
+ }
46
+ if (listInstance && props) {
47
+ throw new ListSubscriptionError(
48
+ "useListSubscription should be passed listInstance or props and crudArgs, not both."
49
+ );
50
+ }
40
51
  if (!listInstance) {
41
- listInstance = useListInstance({ crudArgs, listArgs, retrieveArgs });
52
+ listInstance = useListInstance({ props, functions });
42
53
  }
43
54
  if (!listInstance.state.crud.subscribe) {
44
55
  listInstance.state.crud.subscribe = defaultCrud.subscribe;
@@ -152,12 +163,7 @@ export function useListSubscription({
152
163
  state.errored = computed(() => parentState.errored || state.subscriptionErrored);
153
164
  state.error = computed(() => parentState.error || state.subscriptionError);
154
165
 
155
- state.retrieveArgs = computed(() => parentState.retrieveArgs);
156
- state.listArgs = computed(() => parentState.listArgs);
157
- state.objects = toRef(parentState, "objects");
158
- state.order = toRef(parentState, "order");
159
- state.objectsInOrder = toRef(parentState, "objectsInOrder");
160
- for (let key of passThroughPropertyNames) {
166
+ for (const key of listInstanceStateKeys.filter((key) => !["loading", "errored", "error"].includes(key))) {
161
167
  state[key] = toRef(parentState, key);
162
168
  }
163
169
 
package/use/object.js CHANGED
@@ -2,11 +2,11 @@ import { useObjectCalculated } from "./objectCalculated";
2
2
  import { useObjectInstance } from "./objectInstance";
3
3
  import { useObjectRelated } from "./objectRelated";
4
4
  import { useObjectSubscription } from "./objectSubscription";
5
- import { reactive, shallowReactive, shallowReadonly, toRef } from "vue";
5
+ import { reactive, shallowReadonly, toRef } from "vue";
6
6
 
7
7
  // Manages a chain of useObject* functions
8
8
  export const useObject = ({ props, functions }) => {
9
- const managed = shallowReactive({
9
+ const managed = reactive({
10
10
  objectInstance: null,
11
11
  objectSubscription: null,
12
12
  objectRelated: null,
@@ -32,8 +32,8 @@ export const useObject = ({ props, functions }) => {
32
32
  parentState: managed.objectRelated.state,
33
33
  calculatedObjectRules: toRef(props, "calculatedObjectRules"),
34
34
  });
35
- return shallowReactive({
35
+ return reactive({
36
36
  managed: shallowReadonly(managed),
37
- state: reactive(managed.objectCalculated.state),
37
+ state: managed.objectCalculated.state,
38
38
  });
39
39
  };
@@ -1,8 +1,11 @@
1
- import { keyDiff, loadingCombine } from "../utils";
1
+ import { keyDiff, loadingCombine, useDebugMessage } from "../utils";
2
2
  import { useWatchesRunning } from "./watchesRunning";
3
3
  import isEmpty from "lodash-es/isEmpty";
4
4
  import { computed, effectScope, onScopeDispose, reactive, toRef, watch } from "vue";
5
5
 
6
+ const computedDebugMessage = useDebugMessage(["objectCalculated", "computed"]);
7
+ const watchDebugMessage = useDebugMessage(["objectCalculated", "watch"]);
8
+
6
9
  export function useObjectCalculateds(instances, args) {
7
10
  for (const [key, value] of Object.entries(args)) {
8
11
  useObjectCalculated({
@@ -65,6 +68,7 @@ export function useObjectCalculated({
65
68
  }
66
69
 
67
70
  watch([() => state.calculatedObjectRules && Object.keys(state.calculatedObjectRules)], () => {
71
+ watchDebugMessage("calculatedObjectRules watch called");
68
72
  let addedKeys = [],
69
73
  removedKeys = [],
70
74
  sameKeys = [];
@@ -102,7 +106,12 @@ export function useObjectCalculated({
102
106
  });
103
107
 
104
108
  watchesRunning = useWatchesRunning({
105
- triggerRefs: [computed(() => (!isEmpty(state.calculatedObjectRules) ? parentState.loading : false))],
109
+ triggerRefs: [
110
+ computed(() => {
111
+ computedDebugMessage("watchesRunningTriggerRefs computed");
112
+ return !isEmpty(state.calculatedObjectRules) ? parentState.loading : false;
113
+ }),
114
+ ],
106
115
  watchSentinelRefs: [
107
116
  toRef(state, "parentStateObjectWatchRunning"),
108
117
  toRef(state, "calculatedObjectWatchRunning"),
@@ -110,7 +119,10 @@ export function useObjectCalculated({
110
119
  });
111
120
 
112
121
  state.calculatedRunning = toRef(watchesRunning.state, "running");
113
- state.running = computed(() => loadingCombine(watchesRunning.state.running, parentState.relatedRunning));
122
+ state.running = computed(() => {
123
+ computedDebugMessage("running computed");
124
+ return loadingCombine(watchesRunning.state.running, parentState.relatedRunning);
125
+ });
114
126
 
115
127
  onScopeDispose(() => {
116
128
  for (const key in calculatedObjectEffectScopes) {
@@ -121,10 +133,10 @@ export function useObjectCalculated({
121
133
  }
122
134
  });
123
135
  });
124
- return {
136
+ return reactive({
125
137
  state,
126
138
  parentState,
127
139
  watchesRunning,
128
140
  effectScope: es,
129
- };
141
+ });
130
142
  }
@@ -1,7 +1,7 @@
1
1
  import { addOrUpdateReactiveObject, assignReactiveObject } from "../utils";
2
2
  import cloneDeep from "lodash-es/cloneDeep";
3
3
  import isFunction from "lodash-es/isFunction";
4
- import { reactive, shallowReactive, toRef } from "vue";
4
+ import { reactive, toRef } from "vue";
5
5
 
6
6
  export class ObjectError extends Error {
7
7
  constructor(message) {
@@ -222,7 +222,7 @@ export function useObjectInstance({ props, functions = {} }) {
222
222
  state.error = null;
223
223
  }
224
224
 
225
- return shallowReactive({
225
+ return reactive({
226
226
  state,
227
227
  retrieve,
228
228
  create,
@@ -1,4 +1,4 @@
1
- import { keyDiff } from "../utils";
1
+ import { keyDiff, useDebugMessage } from "../utils";
2
2
  import { useWatchesRunning } from "./watchesRunning";
3
3
  import get from "lodash-es/get";
4
4
  import isArray from "lodash-es/isArray";
@@ -6,6 +6,9 @@ import isEmpty from "lodash-es/isEmpty";
6
6
  import isUndefined from "lodash-es/isUndefined";
7
7
  import { computed, effectScope, onScopeDispose, reactive, toRef, unref, watch } from "vue";
8
8
 
9
+ const computedDebugMessage = useDebugMessage(["objectRelated", "computed"]);
10
+ const watchDebugMessage = useDebugMessage(["objectRelated", "watch"]);
11
+
9
12
  export function useObjectRelateds(instances, args) {
10
13
  for (const [key, value] of Object.entries(args)) {
11
14
  useObjectRelated({
@@ -61,6 +64,7 @@ export function useObjectRelated({
61
64
  }
62
65
 
63
66
  watch([() => state.relatedObjectRules && Object.keys(state.relatedObjectRules)], () => {
67
+ watchDebugMessage("relatedObjectRules changed");
64
68
  let addedRuleKeys = [],
65
69
  removedRuleKeys = [];
66
70
  if (!state.relatedObjectRules) {
@@ -83,6 +87,7 @@ export function useObjectRelated({
83
87
  relatedObjectEffectScopes[addedRuleKey] = effectScope();
84
88
  relatedObjectEffectScopes[addedRuleKey].run(() => {
85
89
  state.relatedObjectObjects[addedRuleKey] = computed(() => {
90
+ computedDebugMessage("relatedObjectObjects computed");
86
91
  // deal with computed objects being passed.
87
92
  const ruleObjects = unref(state.relatedObjectRules?.[addedRuleKey]?.objects);
88
93
  const rulePkKey = state.relatedObjectRules?.[addedRuleKey]?.pkKey || addedRuleKey;
@@ -103,7 +108,12 @@ export function useObjectRelated({
103
108
  });
104
109
 
105
110
  watchesRunning = useWatchesRunning({
106
- triggerRefs: [computed(() => (!isEmpty(state.relatedObjectRules) ? parentState.loading : false))],
111
+ triggerRefs: [
112
+ computed(() => {
113
+ watchDebugMessage("parentStateObjectWatchRunning");
114
+ return !isEmpty(state.relatedObjectRules) ? parentState.loading : false;
115
+ }),
116
+ ],
107
117
  watchSentinelRefs: [
108
118
  toRef(state, "parentStateObjectWatchRunning"),
109
119
  toRef(state, "relatedObjectWatchRunning"),
@@ -119,10 +129,10 @@ export function useObjectRelated({
119
129
  });
120
130
  });
121
131
 
122
- return {
132
+ return reactive({
123
133
  state,
124
134
  parentState,
125
135
  watchesRunning,
126
136
  effectScope: es,
127
- };
137
+ });
128
138
  }
@@ -1,7 +1,7 @@
1
1
  import { assignReactiveObject, loadingCombine } from "../utils";
2
2
  import { useCancellableIntent } from "./cancellableIntent";
3
3
  import { useObjectInstance } from "./objectInstance";
4
- import { computed, effectScope, reactive, shallowReactive, toRef } from "vue";
4
+ import { computed, effectScope, reactive, toRef } from "vue";
5
5
 
6
6
  export class ObjectSubscriptionError extends Error {
7
7
  constructor(message) {
@@ -191,7 +191,7 @@ export function useObjectSubscription({
191
191
  });
192
192
  });
193
193
 
194
- return shallowReactive({
194
+ return reactive({
195
195
  state,
196
196
  objectInstance,
197
197
  subscribeIntent,
@@ -1,6 +1,9 @@
1
- import { loadingCombine } from "../utils";
1
+ import { loadingCombine, useDebugMessage } from "../utils";
2
2
  import { computed, effectScope, reactive, unref, watch } from "vue";
3
3
 
4
+ const computedDebugMessage = useDebugMessage(["watchesRunning", "computed"]);
5
+ const watchDebugMessage = useDebugMessage(["watchesRunning", "watch"]);
6
+
4
7
  export function useWatchesRunning({ triggerRefs, watchSentinelRefs }) {
5
8
  const state = reactive({});
6
9
 
@@ -10,6 +13,7 @@ export function useWatchesRunning({ triggerRefs, watchSentinelRefs }) {
10
13
  watch(
11
14
  triggerRefs,
12
15
  (values) => {
16
+ watchDebugMessage("useWatchesRunning triggerRefs");
13
17
  if (values.every((value) => unref(value))) {
14
18
  watchSentinelRefs.forEach((ref) => {
15
19
  ref.value = true;
@@ -21,7 +25,11 @@ export function useWatchesRunning({ triggerRefs, watchSentinelRefs }) {
21
25
  deep: true,
22
26
  }
23
27
  );
24
- state.running = computed(() => loadingCombine(watchSentinelRefs.map((ref) => ref.value)));
28
+ state.running = computed(() => {
29
+ const values = watchSentinelRefs.map((ref) => ref.value);
30
+ computedDebugMessage("useWatchesRunning running");
31
+ return loadingCombine(values);
32
+ });
25
33
  });
26
34
 
27
35
  return {
@@ -0,0 +1,54 @@
1
+ import inspect from "browser-util-inspect";
2
+ import { unref } from "vue";
3
+
4
+ window.RH_DEBUG = false;
5
+ window.RH_DEBUG_ENABLED_CATEGORIES = {};
6
+ window.RH_DEBUG_DISABLED_CATEGORIES = {};
7
+
8
+ const log = console.log;
9
+ const messageHolder = [];
10
+
11
+ /**
12
+ * @param {String} categoriesString
13
+ * @param {(string|Function)[]} messages
14
+ */
15
+ const doLog = (categoriesString, messages) => {
16
+ if (messages.length > 0) {
17
+ for (const message of messages) {
18
+ messageHolder.push(inspect(unref(typeof message === "function" ? message() : message)));
19
+ }
20
+ log(categoriesString, ...messageHolder);
21
+ messageHolder.length = 0;
22
+ }
23
+ };
24
+
25
+ /**
26
+ *
27
+ * @param {string[]} categories
28
+ * @returns {function(...((string|Function)[]|string|Function)): void}
29
+ */
30
+ export function useDebugMessage(categories) {
31
+ const categoriesSet = new Set(categories);
32
+ const categoriesString = categoriesSet.size > 0 ? `[${Array.from(categoriesSet).join(", ")}]` : "";
33
+ return (...messages) => {
34
+ if (!window.RH_DEBUG) {
35
+ return;
36
+ }
37
+ if (categoriesSet.size > 0) {
38
+ for (const category of categoriesSet) {
39
+ if (window.RH_DEBUG_DISABLED_CATEGORIES[category]) {
40
+ return;
41
+ }
42
+ }
43
+ for (const category of categoriesSet) {
44
+ if (window.RH_DEBUG_ENABLED_CATEGORIES[category]) {
45
+ doLog(categoriesString, messages);
46
+ return;
47
+ }
48
+ }
49
+ }
50
+ if (categoriesSet.size === 0 || Object.keys(window.RH_DEBUG_ENABLED_CATEGORIES).length === 0) {
51
+ doLog(categoriesString, messages);
52
+ }
53
+ };
54
+ }
package/utils/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  export * from "./assignReactiveObject";
2
+ export * from "./debugMessage";
2
3
  export * from "./debugWatch";
3
4
  export * from "./flattenPaths";
4
5
  export * from "./getFakeId";
5
6
  export * from "./keyDiff";
7
+ export * from "./lifecycleDebug";
6
8
  export * from "./loadingCombine";
7
9
  export * from "./set";
8
10
  export * from "./watches";
@@ -0,0 +1,52 @@
1
+ import { useDebugMessage } from "./debugMessage";
2
+ import {
3
+ onActivated,
4
+ onBeforeMount,
5
+ onBeforeUnmount,
6
+ onBeforeUpdate,
7
+ onDeactivated,
8
+ onErrorCaptured,
9
+ onMounted,
10
+ onRenderTracked,
11
+ onRenderTriggered,
12
+ onServerPrefetch,
13
+ onUnmounted,
14
+ onUpdated,
15
+ } from "vue";
16
+
17
+ /**
18
+ * @param {string[]} categories
19
+ */
20
+ export function useLifecycleDebug(categories, includes = [], excludes = []) {
21
+ const lifeCycleFns = {
22
+ onActivated,
23
+ onBeforeMount,
24
+ onBeforeUnmount,
25
+ onBeforeUpdate,
26
+ onDeactivated,
27
+ onErrorCaptured,
28
+ onMounted,
29
+ onRenderTracked,
30
+ onRenderTriggered,
31
+ onServerPrefetch,
32
+ onUnmounted,
33
+ onUpdated,
34
+ };
35
+ const hasIncludes = includes && includes.length > 0;
36
+ const hasExcludes = excludes && excludes.length > 0;
37
+ for (const key in lifeCycleFns) {
38
+ if (hasIncludes && !includes.includes(key)) {
39
+ continue;
40
+ }
41
+ if (hasExcludes && excludes.includes(key)) {
42
+ continue;
43
+ }
44
+ const myCategories = new Set(categories);
45
+ myCategories.add(key);
46
+ const eventString = `${key} called`;
47
+ const debugMessage = useDebugMessage(myCategories);
48
+ lifeCycleFns[key](() => {
49
+ debugMessage(eventString);
50
+ });
51
+ }
52
+ }