ivue 0.0.32 → 0.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.
Files changed (157) hide show
  1. package/.babelrc.json +14 -0
  2. package/.eslintrc.cjs +24 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/compiler.xml +7 -0
  5. package/.idea/infinite-vue.iml +10 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +11 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/php.xml +20 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/.vscode/extensions.json +3 -0
  11. package/LICENSE +19 -0
  12. package/README.md +31 -0
  13. package/demo/App.vue +72 -0
  14. package/demo/components/IVueTest.vue +298 -0
  15. package/demo/components/PreComponent.vue +13 -0
  16. package/demo/components/SubComponent2.vue +45 -0
  17. package/demo/components/TraitsComponent.vue +120 -0
  18. package/demo/components/useIVueTest.vue +136 -0
  19. package/demo/main.ts +21 -0
  20. package/demo/router/index.ts +14 -0
  21. package/demo/tests/IVueTests.ts +255 -0
  22. package/demo/tests/Mouse.ts +79 -0
  23. package/demo/tests/ParentIVueTests.ts +36 -0
  24. package/demo/tests/TApp.ts +15 -0
  25. package/demo/tests/TAuth.ts +23 -0
  26. package/demo/tests/TField.ts +84 -0
  27. package/demo/tests/TMessage.ts +52 -0
  28. package/demo/tests/TRouter.ts +18 -0
  29. package/demo/tests/TUser.ts +19 -0
  30. package/demo/tests/Test.ts +86 -0
  31. package/demo/tests/useField.ts +82 -0
  32. package/demo/tests/useIVueTests.ts +57 -0
  33. package/demo/vite.config.ts +13 -0
  34. package/dist/favicon.ico +0 -0
  35. package/dist/index.es.js +518 -0
  36. package/dist/index.umd.js +1 -0
  37. package/dist/src/behavior.d.ts +72 -0
  38. package/dist/src/config.d.ts +6 -0
  39. package/dist/src/index.d.ts +21 -0
  40. package/dist/src/ivue.d.ts +35 -0
  41. package/dist/src/kernel.d.ts +182 -0
  42. package/dist/src/traits/UseCapsule.d.ts +9 -0
  43. package/dist/src/traits/UseEmit.d.ts +3 -0
  44. package/dist/src/traits/UseInstance.d.ts +6 -0
  45. package/dist/src/traits/UseMounting.d.ts +11 -0
  46. package/dist/src/traits/UseRefs.d.ts +8 -0
  47. package/dist/src/traits/UseRoute.d.ts +3 -0
  48. package/dist/src/traits/UseRouter.d.ts +3 -0
  49. package/dist/src/traits/UseRouting.d.ts +6 -0
  50. package/dist/src/traits/UseTick.d.ts +4 -0
  51. package/dist/src/traits/UseVue.d.ts +13 -0
  52. package/dist/src/types/core.d.ts +46 -0
  53. package/dist/src/utils/dispose-garbage.d.ts +12 -0
  54. package/dist/src/utils/extend.d.ts +12 -0
  55. package/dist/src/utils/getters.d.ts +21 -0
  56. package/dist/src/utils/index.d.ts +7 -0
  57. package/dist/src/utils/is.d.ts +14 -0
  58. package/dist/src/utils/pre.d.ts +9 -0
  59. package/dist/src/utils/raw.d.ts +12 -0
  60. package/dist/src/utils/safe-class-name.d.ts +7 -0
  61. package/dist/src/utils/traits.d.ts +41 -0
  62. package/env.d.ts +1 -0
  63. package/index.html +13 -0
  64. package/package-lock.json +14305 -0
  65. package/package.json +89 -10
  66. package/public/favicon.ico +0 -0
  67. package/src/App/App.ts +27 -0
  68. package/src/App/Auth/Auth.ts +105 -0
  69. package/src/App/Auth/Auth.vue +98 -0
  70. package/src/App/Auth/Logout.vue +14 -0
  71. package/src/App/Auth/User.ts +6 -0
  72. package/src/App/BlackBox.ts +75 -0
  73. package/src/App/Config.ts +6 -0
  74. package/src/App/Generators/generators.ts +47 -0
  75. package/src/App/Home/Home.vue +16 -0
  76. package/src/App/Services/Http/FakeHttp.ts +8 -0
  77. package/src/App/Services/Http/Http.ts +51 -0
  78. package/src/App/Services/Message/Message.ts +49 -0
  79. package/src/App/Services/Message/Message.vue +15 -0
  80. package/src/App/Services/Navigation/Navigation.ts +83 -0
  81. package/src/App/Services/Navigation/Navigation.vue +59 -0
  82. package/src/App/Services/Routing/FakeRouter.ts +7 -0
  83. package/src/App/Services/Routing/NotFoundRoute.vue +13 -0
  84. package/src/App/Services/Routing/Router.ts +262 -0
  85. package/src/App/Services/Routing/Routes.ts +49 -0
  86. package/src/App/Stubs/SingleBookResultStub.ts +13 -0
  87. package/src/App/Traits/UseApp.ts +6 -0
  88. package/src/App/Traits/UseBlackline.ts +0 -0
  89. package/src/App/Traits/UseQuasar.ts +8 -0
  90. package/src/behavior.ts +269 -0
  91. package/src/config.ts +15 -0
  92. package/src/dev/dev-utils.ts +78 -0
  93. package/src/index.ts +83 -0
  94. package/src/ivue.ts +296 -0
  95. package/src/kernel.ts +810 -0
  96. package/src/tests/auth.spec.ts +48 -0
  97. package/src/traits/UseCapsule.ts +28 -0
  98. package/src/traits/UseEmit.ts +3 -0
  99. package/src/traits/UseInstance.ts +17 -0
  100. package/src/traits/UseMounting.ts +23 -0
  101. package/src/traits/UseRefs.ts +17 -0
  102. package/src/traits/UseRoute.ts +6 -0
  103. package/src/traits/UseRouter.ts +5 -0
  104. package/src/traits/UseRouting.ts +7 -0
  105. package/src/traits/UseTick.ts +5 -0
  106. package/src/traits/UseVue.ts +38 -0
  107. package/src/types/core.ts +64 -0
  108. package/src/utils/dispose-garbage.ts +34 -0
  109. package/src/utils/extend.ts +85 -0
  110. package/src/utils/getters.ts +62 -0
  111. package/src/utils/index.ts +16 -0
  112. package/src/utils/is.ts +22 -0
  113. package/src/utils/pre.ts +29 -0
  114. package/src/utils/raw.ts +19 -0
  115. package/src/utils/safe-class-name.ts +15 -0
  116. package/src/utils/traits.ts +121 -0
  117. package/tsconfig.app.json +47 -0
  118. package/tsconfig.json +14 -0
  119. package/tsconfig.node.json +14 -0
  120. package/tsconfig.vitest.json +9 -0
  121. package/vite.config.ts +55 -0
  122. package/vitest.config.ts +18 -0
  123. package/dist/index.js +0 -218
  124. package/docs/index.html +0 -195
  125. package/docs/index.json +0 -3
  126. package/docs/input.html +0 -41
  127. package/docs/items.html +0 -42
  128. package/gulpfile.js +0 -5
  129. package/src/components/checkbox.js +0 -47
  130. package/src/components/data.js +0 -6
  131. package/src/components/file.js +0 -40
  132. package/src/components/form.js +0 -7
  133. package/src/components/index.js +0 -15
  134. package/src/components/input.js +0 -80
  135. package/src/components/items.js +0 -65
  136. package/src/components/modal.js +0 -42
  137. package/src/components/paginate-old.js +0 -88
  138. package/src/components/paginate.js +0 -35
  139. package/src/components/select-search.js +0 -152
  140. package/src/components/select.js +0 -62
  141. package/src/components/submit.js +0 -10
  142. package/src/components/textarea.js +0 -72
  143. package/src/components/upload.js +0 -49
  144. package/src/directives/href.js +0 -10
  145. package/src/directives/index.js +0 -1
  146. package/src/filters/date.js +0 -3
  147. package/src/filters/datetime.js +0 -3
  148. package/src/filters/index.js +0 -4
  149. package/src/filters/json.js +0 -3
  150. package/src/filters/money.js +0 -3
  151. package/src/index.js +0 -4
  152. package/src/mixins/data.js +0 -13
  153. package/src/mixins/form.js +0 -85
  154. package/src/mixins/resource.js +0 -31
  155. package/src/services/client.js +0 -32
  156. package/src/services/flash.js +0 -17
  157. package/src/services/index.js +0 -2
@@ -0,0 +1,48 @@
1
+ import { describe, it, beforeEach, expect, vi } from 'vitest'
2
+ import { BlackBox } from '../App/BlackBox'
3
+ import type { App } from '@/App/App';
4
+
5
+ let box: BlackBox
6
+ let app: App
7
+
8
+ function wait () {
9
+ return setTimeout(() => {})
10
+ }
11
+
12
+ describe('--- auth test ----', () => {
13
+
14
+ beforeEach(() => {
15
+ box = new BlackBox().init()
16
+ app = box.app
17
+ })
18
+
19
+ it('root route redirects to login', async () => {
20
+ await app.router.push({ name: 'root' })
21
+ expect(app.router.active.name).toBe('login')
22
+ })
23
+
24
+ it('successful login redirects to homepage', async () => {
25
+ await app.router.push({ name: 'root' })
26
+
27
+ app.auth.email = 'ekalashnikov@gmail.com'
28
+ app.auth.password = 'test1234'
29
+
30
+ const spy = vi.spyOn(app.router, 'push')
31
+
32
+ await app.auth.login()
33
+
34
+ expect(spy).toHaveBeenCalledTimes(1)
35
+ expect(spy).toHaveBeenCalledWith({ name: 'home' })
36
+
37
+ expect(app.message.appMessages).toEqual(['User logged in'])
38
+
39
+ expect(app.user.email).toBe('ekalashnikov@gmail.com')
40
+ expect(app.user.token).toBe('1234ekalashnikov@gmail.com')
41
+
42
+ await app.router.isLoaded()
43
+
44
+ expect(app.router.currentRoute.name).toBe('home')
45
+ })
46
+
47
+ })
48
+
@@ -0,0 +1,28 @@
1
+ import { get, make, use, init } from '../kernel';
2
+ import type { AnyClass } from '../types/core';
3
+ import { markRaw } from 'vue';
4
+
5
+ export class UseCapsule {
6
+
7
+ $!: InstanceType<this['capsule']>
8
+
9
+ capsule: AnyClass | any
10
+
11
+ useCapsule (args: any = []) {
12
+ this.$ = use(this.capsule, this, ...args)
13
+ markRaw(this.$)
14
+ }
15
+
16
+ initCapsule (args: any = []) {
17
+ this.$ = init(this.capsule, this, ...args)
18
+ markRaw(this.$)
19
+ }
20
+
21
+ getCapsule (args: any = []) {
22
+ this.$ = get(this.capsule, this, ...args)
23
+ }
24
+
25
+ makeCapsule (args: any = []) {
26
+ this.$ = make(this.capsule, this, ...args)
27
+ }
28
+ }
@@ -0,0 +1,3 @@
1
+ export class UseEmit {
2
+ $emit: Function = (...args:any) => {}
3
+ }
@@ -0,0 +1,17 @@
1
+ import type { Class } from '../types/core'
2
+ import { IVUE } from '../behavior';
3
+ import { extend } from '../utils/extend'
4
+ import { getCurrentInstance } from 'vue';
5
+
6
+ export function useInstance (mainClass: Class, self: UseInstance | any) {
7
+ mainClass.behavior = extend(mainClass.behavior ?? {}, { $instance: IVUE.OFF })
8
+ }
9
+
10
+ export class UseInstance {
11
+ get $instance () {
12
+ return getCurrentInstance()
13
+ }
14
+ constructor (mainClass: Class) {
15
+ useInstance(mainClass, this)
16
+ }
17
+ }
@@ -0,0 +1,23 @@
1
+ import { type Class } from '../types/core';
2
+ import { after } from '../behavior'
3
+ import { onMounted, onUnmounted, onBeforeMount, onBeforeUnmount } from 'vue'
4
+
5
+ export function useMounting (mainClass: Class, obj: UseMounting | any) {
6
+ after(mainClass, ({ self }) => {
7
+ if ('beforeMount' in self) onBeforeMount(() => self.beforeMount())
8
+ if ('mounted' in self) onMounted(() => self.mounted())
9
+ if ('beforeUnmount' in self) onBeforeUnmount(() => self.beforeUnmount())
10
+ if ('unmounted' in self) onUnmounted(() => self.unmounted())
11
+ })
12
+ }
13
+
14
+ /** Make a class useMounting to a Vue component */
15
+ export class UseMounting {
16
+ constructor (mainClass: Class) {
17
+ useMounting(mainClass, this)
18
+ }
19
+ beforeMount?: ReturnType<typeof onBeforeMount> = function () {}
20
+ mounted?: ReturnType<typeof onMounted> = function () {}
21
+ beforeUnmount?: ReturnType<typeof onBeforeUnmount> = function () {}
22
+ unmounted?: ReturnType<typeof onUnmounted> = function () {}
23
+ }
@@ -0,0 +1,17 @@
1
+ import type { Class } from '../types/core';
2
+ import { IVUE } from '../behavior';
3
+ import { extend } from '../utils/extend'
4
+ import { getCurrentInstance } from 'vue';
5
+
6
+ export function useRefs (mainClass: Class, obj: any) {
7
+ mainClass.behavior = extend(mainClass.behavior ?? {}, { $refs: IVUE.OFF })
8
+ }
9
+
10
+ export class UseRefs {
11
+ get $refs () {
12
+ return getCurrentInstance()?.refs;
13
+ }
14
+ constructor (mainClass: Class) {
15
+ useRefs(mainClass, this)
16
+ }
17
+ }
@@ -0,0 +1,6 @@
1
+ import { toValue } from 'vue';
2
+ import { config } from '../config';
3
+
4
+ export class UseRoute {
5
+ get route () { return toValue(config.router?.currentRoute) }
6
+ }
@@ -0,0 +1,5 @@
1
+ import { config } from '../config';
2
+
3
+ export class UseRouter {
4
+ get router () { return config.router }
5
+ }
@@ -0,0 +1,7 @@
1
+ import { Traits } from '../utils/traits';
2
+ import { UseRouter } from './UseRouter';
3
+ import { UseRoute } from './UseRoute';
4
+
5
+ export class UseRouting {}
6
+ Traits(UseRouting, [UseRouter, UseRoute])
7
+ export interface UseRouting extends UseRouter, UseRoute {}
@@ -0,0 +1,5 @@
1
+ import { nextTick } from 'vue';
2
+
3
+ export class UseTick {
4
+ $nextTick = nextTick
5
+ }
@@ -0,0 +1,38 @@
1
+ import type { Class } from '../types/core'
2
+ import { Traits } from '../utils/traits';
3
+ import { useMounting, UseMounting } from './UseMounting';
4
+ import { UseRouting } from './UseRouting';
5
+ import { useRefs, UseRefs } from './UseRefs';
6
+ import { UseEmit } from './UseEmit';
7
+ import { UseTick } from './UseTick';
8
+ import { UseInstance, useInstance } from './UseInstance';
9
+
10
+ export function useVue (mainClass: Class, obj: UseVue | any) {
11
+ useInstance(mainClass, obj)
12
+ useRefs(mainClass, obj)
13
+ useMounting(mainClass, obj)
14
+ }
15
+
16
+ export class UseVue {
17
+ constructor (mainClass: Class) {
18
+ useVue(mainClass, this)
19
+ }
20
+ }
21
+
22
+ Traits(UseVue, [
23
+ UseRouting,
24
+ UseMounting,
25
+ UseEmit,
26
+ UseTick,
27
+ UseRefs,
28
+ UseInstance
29
+ ])
30
+
31
+ export interface UseVue
32
+ extends
33
+ UseRouting,
34
+ UseMounting,
35
+ UseEmit,
36
+ UseTick,
37
+ UseRefs,
38
+ UseInstance {}
@@ -0,0 +1,64 @@
1
+ import type { Mapping } from '../kernel'
2
+ import type { ComputedRef } from 'vue';
3
+
4
+ export type AnyClass = abstract new (...args: any) => any;
5
+
6
+ export type Class = {
7
+ behavior?: any;
8
+ new(...args: any[]): any;
9
+ [x: string | symbol]: any
10
+ }
11
+
12
+ export type IVue<T extends AnyClass> = InstanceType<T> & IVueToRefs<T>
13
+
14
+ /**
15
+ * @see ivueTransform
16
+ */
17
+ export interface IVueToRefs<T extends AnyClass> {
18
+ toRefs: (...args: any) => InstanceType<T>
19
+ }
20
+
21
+ export interface IVueToRefsObj<T extends object> {
22
+ toRefs: (...args: any) => T
23
+ }
24
+
25
+ export type MappingScope = 'singleton' | 'transient'
26
+
27
+ export type MappingType = 'generic' | 'ivue' | any
28
+
29
+ export type InferredArgs<T> = T extends { new(...args: infer P): any } ? P : never[]
30
+
31
+ export type Getters = Map<string | symbol | number, PropertyDescriptor>
32
+
33
+ export interface Intercept {
34
+ return: any,
35
+ mapping: Mapping,
36
+ name?: string,
37
+ self: any,
38
+ args: any
39
+ }
40
+
41
+ export type InterceptOptions = {
42
+ top: boolean,
43
+ scoped: boolean
44
+ }
45
+
46
+ export type InterceptFn = (intercept: Intercept, self: Object, prop: string) => void | true
47
+
48
+ export type InterceptsMap = {
49
+ before: Map<Function | Class, InterceptFn[]>,
50
+ after: Map<Function | Class, InterceptFn[]>
51
+ }
52
+
53
+ export type InterceptAttachTo = Function | [Class, Function]
54
+
55
+ export type InterceptsFns = InterceptFn[] | undefined | any
56
+
57
+ export type Null<T> = T | null
58
+
59
+ export type AnyObj = Record<string | number | symbol, any>
60
+
61
+ export type Params<T extends (...args: any) => any> = Parameters<T>
62
+
63
+
64
+ export type Computeds = Record<string | symbol | number, ComputedRef>
@@ -0,0 +1,34 @@
1
+ import { toRaw } from "vue"
2
+ import type { AnyClass, Getters, IVue } from ".."
3
+ const propertiesMap = new WeakMap()
4
+ /**
5
+ * Advanced garbage disposal for complete memory control.
6
+ * Disposes an internal object that is under the vue reactive proxy.
7
+ * To expose the raw property, toRaw(vue) method is used
8
+ * to retrieve the original object.
9
+ *
10
+ * @param vue ivue instance
11
+ * @param getters @see Getters
12
+ * @param name string
13
+ */
14
+ export const disposeGarbage = <T extends AnyClass> (vue: IVue<T> | any) => {
15
+ // Deep garbage collection, gives really amazing performance in Opera as well as Google Chrome.
16
+ // Opera seems to perform better though with cleaning up the garbage more effeciently and more.
17
+
18
+ let instance = toRaw(vue)
19
+ let props: any = Object.getOwnPropertyNames(instance)
20
+
21
+ for (let i = 0; i < props.length; i++) {
22
+ delete instance[props[i]]
23
+ }
24
+
25
+ // Faster but less thorough garbage collection:
26
+ // Will remove only enumerable properties.
27
+ // for (prop in vue) {
28
+ // delete vue[prop]
29
+ // }
30
+
31
+ // Unset roots for gc engine to collect and dispose
32
+ instance = null
33
+ props = null
34
+ }
@@ -0,0 +1,85 @@
1
+ import { isObject, isPromise } from "./is";
2
+
3
+ /**
4
+ * Advanced deep merge of two or more objects.
5
+ * Merges sources into target iterating from left to right.
6
+ * Supports circular references and promises.
7
+ * Merges and modifies the target object.
8
+ * Only simple objects can extend the target, yet the
9
+ * target can be anything, even a class object.
10
+ *
11
+ * @param target object
12
+ * @param sources array
13
+ */
14
+ export function extend (target: any, ...sources: any[]) {
15
+ let parents: any = new WeakMap() // parents object to detect circular references
16
+ const result = _extend(target, [...sources], parents);
17
+ // parents = undefined // flush the parents map upon completion
18
+ return result
19
+ }
20
+
21
+ /**
22
+ * Deep merge two objects inner function.
23
+ *
24
+ * @param target Target - object to merge into.
25
+ * @param sources Sources - object to merge from.
26
+ * @param parents Parents - for circular reference checks.
27
+ * @return {*}
28
+ *
29
+ * @internal
30
+ */
31
+ function _extend<K, V> (target: any, sources: any[], parents: Map<K, V> | null | any = null) {
32
+
33
+ if (!sources.length) return target;
34
+ // save target object in Map as a key
35
+ parents.set(target, true)
36
+
37
+ const source = sources.shift();
38
+
39
+ if (isObject(target) && isObject(source)) {
40
+
41
+ for (const key in source) {
42
+ if (isObject(source[key]) && source[key].constructor.name === 'Object') {
43
+ // detect circular references using Map parents object
44
+ if (parents.has(source[key])) {
45
+ // console.log('detected circular reference key:', key,
46
+ // 'value:', source[key],
47
+ // 'parents:', [...parents])
48
+ target[key] = source[key]
49
+ } else {
50
+ if (isPromise(source[key])) {
51
+ // promise objects should not be assigned
52
+ // via _extend
53
+ target[key] = source[key]
54
+ } else {
55
+ // the following lines
56
+ // integrate Proxy support
57
+ // if the target key does not exist
58
+ if (typeof target[key] === 'undefined') {
59
+ // assign directly the proxy or any other object
60
+ target[key] = source[key]
61
+ } else {
62
+ // if target[key] is not an object
63
+ // convert it to an object to be able to extend
64
+ if (!isObject(target[key])) {
65
+ target[key] = source[key]
66
+ } else {
67
+ // Only simple objects can extend the target
68
+ if (target[key].constructor.name !== 'Object') {
69
+ target[key] = source[key]
70
+ } else {
71
+ _extend(target[key], [source[key]], parents)
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ } else {
79
+ target[key] = source[key]
80
+ }
81
+ }
82
+ }
83
+
84
+ return _extend(target, sources, parents);
85
+ }
@@ -0,0 +1,62 @@
1
+ import type { Getters } from '../types/core'
2
+
3
+ /**
4
+ * Store all getters for each class prototype processed by getPrototypeGetters.
5
+ * @see getPrototypeGetters
6
+ */
7
+ export const gettersMap = new Map()
8
+
9
+ /**
10
+ * Get getters of a class prototype as a map.
11
+ *
12
+ * @param proto
13
+ * @return Getters
14
+ */
15
+ export function getPrototypeGetters (proto: object | null) {
16
+
17
+ if (gettersMap.has(proto)) return gettersMap.get(proto)
18
+
19
+ const initialProto = proto
20
+
21
+ const props: any[] = []
22
+
23
+ while (proto && proto.constructor.name !== 'Object') {
24
+ props.push.apply(props, Object.entries(
25
+ Object.getOwnPropertyDescriptors(proto)
26
+ ))
27
+ proto = Object.getPrototypeOf(proto.constructor.prototype)
28
+ }
29
+
30
+ const getters: Getters = new Map()
31
+
32
+ for (let i = 0; i < props.length; i++) {
33
+ if (props[i][0] !== '__proto__' && typeof props[i][1].get === 'function') {
34
+ getters.set(props[i][0], props[i][1])
35
+ }
36
+ }
37
+ /**
38
+ * Save getters in the getters map.
39
+ */
40
+ gettersMap.set(initialProto, getters)
41
+
42
+ return getters
43
+ }
44
+
45
+ /**
46
+ * Get getters of a class instance and the total number of them.
47
+ * @param instance Object instance
48
+ * @returns Getter descriptors
49
+ */
50
+ export function getInstanceGetters (instance: { [x: string]: any; }) {
51
+
52
+ const getters: Getters = new Map()
53
+ const props = Object.entries(Object.getOwnPropertyDescriptors(instance))
54
+
55
+ for (let i = 0; i < props.length; i++) {
56
+ if (typeof props[i][1].get === 'function' && props[i][0] !== '__proto__') {
57
+ getters.set(props[i][0], props[i][1])
58
+ }
59
+ }
60
+
61
+ return getters
62
+ }
@@ -0,0 +1,16 @@
1
+ import { raw, unraw } from './raw'
2
+ import { extend } from './extend'
3
+ import { Traits } from './traits'
4
+ import { getPrototypeGetters, getInstanceGetters } from './getters'
5
+ import { safeClassName } from './safe-class-name';
6
+ import { pre } from './pre';
7
+ export {
8
+ raw,
9
+ unraw,
10
+ extend,
11
+ Traits,
12
+ getPrototypeGetters,
13
+ getInstanceGetters,
14
+ safeClassName,
15
+ pre
16
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Determine if the value is a true Object.
3
+ *
4
+ * @param v any value
5
+ * @returns boolean
6
+ */
7
+ export function isObject (v: any) {
8
+ return (v && typeof v === 'object' && !Array.isArray(v));
9
+ }
10
+
11
+ /**
12
+ * Determine if the value is a Promise.
13
+ *
14
+ * @param v any value
15
+ * @returns boolean
16
+ */
17
+ export function isPromise (v: any) {
18
+ return v !== null &&
19
+ typeof v === 'object' &&
20
+ typeof v.then === 'function' &&
21
+ typeof v.catch === 'function';
22
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Pretty print an object that can contain circular references.
3
+ *
4
+ * @param v object to print
5
+ * @param spaces number of spaces for tabs
6
+ * @returns pretty string
7
+ * @source https://stackoverflow.com/a/48254637
8
+ */
9
+ export function pre (v: any, spaces = 2) {
10
+ const cache = new Set();
11
+ return JSON.stringify(v, function (key, value) {
12
+ if (typeof value === 'object' && value !== null) {
13
+ if (cache.has(value)) {
14
+ // Circular reference found
15
+ try {
16
+ // If this value does not reference a parent it can be deduped
17
+ return JSON.parse(JSON.stringify(value))
18
+ }
19
+ catch (err) {
20
+ // discard key if value cannot be deduped
21
+ return '[**circular**]';
22
+ }
23
+ }
24
+ // Store value in our set
25
+ cache.add(value)
26
+ }
27
+ return value;
28
+ }, spaces)
29
+ }
@@ -0,0 +1,19 @@
1
+ import { markRaw } from 'vue';
2
+
3
+ /**
4
+ * Convert object back to Vue reactive.
5
+ *
6
+ * @param obj
7
+ */
8
+ export function unraw (obj: any) {
9
+ delete obj.__v_skip
10
+ }
11
+
12
+ /**
13
+ * Alias for Vue markRaw() function.
14
+ *
15
+ * @param obj
16
+ */
17
+ export function raw (obj: any) {
18
+ return markRaw(obj)
19
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Convert class name, symbol to string.
3
+ *
4
+ * @param className
5
+ * @returns
6
+ */
7
+ export function safeClassName(className: any) {
8
+ let name = ''
9
+ try {
10
+ name = className?.name || String(className)
11
+ } catch (e) {
12
+ name = 'Unknown[failed to convert to string]'
13
+ }
14
+ return name
15
+ }
@@ -0,0 +1,121 @@
1
+ import type { Class } from '../types/core'
2
+
3
+ /**
4
+ * Traits architecture that supports methods, properties, getters and setters.
5
+ *
6
+ * Traits override each other, while traits can set new props onto
7
+ * the main prototype, they cannot override the main prototypes'
8
+ * props if the main prototype had them already initially.
9
+ *
10
+ * Traits override each other, left most traits having higher priority, matching
11
+ * TypeScript's interface `interface Class extends Trait1, Trait2, Trait3 {}`
12
+ * architecture, enabling us to have full TypeScript & IDE support:
13
+ *
14
+ * Example:
15
+ * ```ts
16
+ * class MainClass {}
17
+ *
18
+ * class Trait1 {
19
+ * get prop () { return 3 }
20
+ * }
21
+ *
22
+ * class Trait2 {
23
+ * get prop () { return 2 }
24
+ * }
25
+ *
26
+ * class Trait3 {
27
+ * get prop () { return 3 }
28
+ * }
29
+ *
30
+ * Traits(MainClass, [Trait1, Trait2, Trait3])
31
+ * export interface MainClass extends Trait1, Trait2, Trait3 {}
32
+ * ```
33
+ *
34
+ * Trait1 props will override Traits2 & Traits3 properties,
35
+ * but will not override MainClass properties if set.
36
+ *
37
+ * Inspired by TypeScript docs: https://www.typescriptlang.org/docs/handbook/mixins.html#alternative-pattern
38
+ *
39
+ * @param main
40
+ * @param traits
41
+ */
42
+ export function Traits (main: Class, traits: Class[]): void {
43
+
44
+ const initialProtoSetterOnly: Record<string | number | symbol, Function> = {}
45
+
46
+ const initialProto = Object.getOwnPropertyNames(main.prototype)
47
+ .reduce((acc: any, prop: string) => {
48
+ const descriptor = Object.getOwnPropertyDescriptor(main.prototype, prop)
49
+ let skip = false
50
+ // skip setters without getters
51
+ if (descriptor?.set && !descriptor?.get) {
52
+ // collect setter only descriptors
53
+ initialProtoSetterOnly[prop] = descriptor?.set
54
+ skip = true
55
+ }
56
+ if (!skip) acc[prop] = true
57
+ return acc
58
+ }, {})
59
+
60
+ const notInInitialProto: Record<string, boolean> = {}
61
+
62
+ traits.reverse().forEach(trait => {
63
+
64
+ // Init the traits constructor to be able to perform
65
+ // transformations on the main class beyond
66
+ // just property & method inheritance.
67
+ const obj = new trait(main)
68
+
69
+ // Loop initialized properties, otherwise they are undefined
70
+ for (const prop in obj) {
71
+
72
+ if (!(prop in initialProto)) notInInitialProto[prop] = true
73
+
74
+ // Did prop exist on the initial state of main prototype?
75
+ // If it did, we do not want to override it
76
+ if (prop in notInInitialProto) {
77
+ Object.defineProperty(
78
+ main.prototype,
79
+ prop,
80
+ {
81
+ value: obj[prop],
82
+ writable: true
83
+ }
84
+ )
85
+ }
86
+ }
87
+
88
+ // Loop through all properties to get the methods
89
+ Object.getOwnPropertyNames(trait.prototype).forEach(prop => {
90
+ if (prop !== 'constructor') {
91
+
92
+ if (!(prop in initialProto)) notInInitialProto[prop] = true
93
+
94
+ // Did prop exist on the initial state of main prototype?
95
+ // If it did, we do not want to override it
96
+ if (prop in notInInitialProto) {
97
+ const descriptor = Object.getOwnPropertyDescriptor(trait.prototype, prop) || Object.create(null)
98
+
99
+ // This is to ensure that setters from other traits are passed down
100
+ // but only if the initialProto has no setter set
101
+ if (descriptor?.set && !(prop in initialProtoSetterOnly)) {
102
+ initialProtoSetterOnly[prop] = descriptor?.set
103
+ }
104
+
105
+ // This is to ensure the initialProto with set only does not get overriden
106
+ // with traits that do not have a setter, but only have a getter
107
+ if (descriptor?.get && !descriptor?.set && prop in initialProtoSetterOnly) {
108
+ descriptor.set = initialProtoSetterOnly[prop]
109
+ }
110
+
111
+ Object.defineProperty(
112
+ main.prototype,
113
+ prop,
114
+ descriptor
115
+ )
116
+ }
117
+
118
+ }
119
+ })
120
+ })
121
+ }