diff --git a/packages/x-components/package.json b/packages/x-components/package.json index dd51bf85e6..5308b3c240 100644 --- a/packages/x-components/package.json +++ b/packages/x-components/package.json @@ -101,7 +101,7 @@ "@types/jest": "~27.5.0", "@types/node": "~18.19.0", "@types/testing-library__jest-dom": "~5.14.5", - "@vitejs/plugin-vue": "^5.0.4", + "@vitejs/plugin-vue": "~5.0.5", "@vue/test-utils": "~2.4.6", "autoprefixer": "~10.4.4", "convert-source-map": "~2.0.0", @@ -127,7 +127,7 @@ "ts-node": "~10.9.1", "typescript": "~4.9.4", "vite": "^4.5.0", - "vite-plugin-vue-inspector": "^5.1.2", + "vite-plugin-vue-inspector": "~5.1.2", "vue": "~3.4.31", "vue-docgen-cli": "~4.79.0", "vue-router": "~4.4.0", diff --git a/packages/x-components/src/components/decorators/__tests__/bus.decorators.spec.ts b/packages/x-components/src/components/decorators/__tests__/bus.decorators.spec.ts deleted file mode 100644 index 85f6d86e89..0000000000 --- a/packages/x-components/src/components/decorators/__tests__/bus.decorators.spec.ts +++ /dev/null @@ -1,390 +0,0 @@ -import { createLocalVue, mount, VueClass, Wrapper } from '@vue/test-utils'; -import Vue, { CreateElement, VNode, VueConstructor } from 'vue'; -import { Component, Prop } from 'vue-property-decorator'; -import Vuex, { Store } from 'vuex'; -import { - createHierarchicalFilter, - createSimpleFilter -} from '../../../__stubs__/filters-stubs.factory'; -import { installNewXPlugin } from '../../../__tests__/utils'; -import { XEvent, XEventPayload } from '../../../wiring/events.types'; -import { searchBoxXStoreModule } from '../../../x-modules/search-box/store/module'; -import { searchBoxXModule } from '../../../x-modules/search-box/x-module'; -import { xComponentMixin } from '../../x-component.mixin'; -import { XEmit, XOn } from '../bus.decorators'; -import Mock = jest.Mock; - -describe('testing @XOn decorator', () => { - const createdListener = jest.fn(); - const dataListener = jest.fn(); - const multipleListener = jest.fn(); - const singleListener = jest.fn(); - const optionsListener = jest.fn(); - const filteredOptionsListener = jest.fn(); - const filteredWithMultipleOptionsListener = jest.fn(); - - @Component({ - mixins: [xComponentMixin(searchBoxXModule)] - }) - class TestingComponent extends Vue { - protected events: XEvent[] = ['UserIsTypingAQuery', 'UserTalked']; - - created(): void { - createdListener(this); - } - - render(createElement: CreateElement): VNode { - return createElement(); - } - - @XOn(component => (component as TestingComponent).events) - testingXOnData(payload: unknown): void { - dataListener(this, payload); - } - - @XOn(['UserClickedOpenEventsModal', 'UserClickedCloseEventsModal']) - testingXOnMultiple(): void { - multipleListener(this); - } - - @XOn('UserClickedCloseEventsModal', { moduleName: 'searchBox', feature: 'search_box' }) - testingXOnMultipleOptionsFiltered(): void { - filteredWithMultipleOptionsListener(this); - } - - @XOn('UserClickedOpenEventsModal', { moduleName: 'searchBox' }) - testingXOnOptions(): void { - optionsListener(this); - } - - @XOn('UserClickedCloseEventsModal', { moduleName: 'empathize' }) - testingXOnOptionsFiltered(): void { - filteredOptionsListener(this); - } - - @XOn('UserAcceptedAQuery') - testingXOnSingle(payload: string): void { - singleListener(this, payload); - } - } - - let component: Wrapper; - let localVue: VueConstructor; - - beforeEach(() => { - component?.vm.$destroy(); - jest.clearAllMocks(); - localVue = createLocalVue(); - localVue.use(Vuex); - const store = new Store({ - modules: { - x: { - namespaced: true, - modules: { - searchBox: { namespaced: true, ...searchBoxXStoreModule } as any - } - } - } - }); - installNewXPlugin({}, localVue); - - component = mount(TestingComponent, { - localVue, - store - }); - }); - - it('calls original created hook', () => { - expect(createdListener).toHaveBeenCalledWith(component.vm); - }); - - it('subscribes to a defined event', () => { - component.vm.$x.emit('UserAcceptedAQuery', 'algo grasioso'); - - expect(singleListener).toHaveBeenCalled(); - expect(singleListener).toHaveBeenCalledWith(component.vm, 'algo grasioso'); - }); - - it('subscribes to a defined array of events', () => { - component.vm.$x.emit('UserClickedOpenEventsModal'); - component.vm.$x.emit('UserClickedCloseEventsModal'); - - expect(multipleListener).toHaveBeenCalledTimes(2); - }); - - it('subscribes dynamically to the events defined in a data property', async () => { - component.vm.$x.emit('UserIsTypingAQuery', 'algo grasioso'); - component.vm.$x.emit('UserTalked', 'algo chistoso'); - - expect(dataListener).toHaveBeenNthCalledWith(1, component.vm, 'algo grasioso'); - expect(dataListener).toHaveBeenNthCalledWith(2, component.vm, 'algo chistoso'); - - (component.vm as any).events = ['UserClearedQuery']; - await localVue.nextTick(); - dataListener.mockClear(); - - component.vm.$x.emit('UserIsTypingAQuery', 'algo grasioso'); - component.vm.$x.emit('UserTalked', 'algo chistoso'); - expect(dataListener).not.toHaveBeenCalled(); - - component.vm.$x.emit('UserClearedQuery', ''); - expect(dataListener).toHaveBeenCalled(); - }); - - it('un-subscribes to any subscribed event when destroying the component', () => { - component.vm.$destroy(); - component.vm.$x.emit('UserAcceptedAQuery', 'que pasara que misterios habra'); - component.vm.$x.emit('UserIsTypingAQuery', 'estare escribiendo?'); - component.vm.$x.emit('UserTalked', 'no he dicho nada'); - component.vm.$x.emit('UserClickedOpenEventsModal'); - component.vm.$x.emit('UserClickedCloseEventsModal'); - - expect(singleListener).not.toHaveBeenCalled(); - expect(multipleListener).not.toHaveBeenCalled(); - expect(dataListener).not.toHaveBeenCalled(); - }); - - it('filters out callback based on options passed to the decorator', () => { - component.vm.$x.emit('UserClickedOpenEventsModal'); - expect(optionsListener).toHaveBeenCalled(); - component.vm.$x.emit('UserClickedCloseEventsModal'); - expect(filteredOptionsListener).not.toHaveBeenCalled(); - }); - - it('filters out callback based on multiple options passed to the decorator', () => { - component.vm.$x.emit('UserClickedCloseEventsModal', undefined, { feature: 'url' }); - expect(filteredWithMultipleOptionsListener).not.toHaveBeenCalled(); - component.vm.$x.emit('UserClickedCloseEventsModal', undefined, { feature: 'search_box' }); - expect(filteredWithMultipleOptionsListener).toHaveBeenCalled(); - }); -}); - -describe('testing @XEmit decorator', () => { - interface RenderXEmitTestOptions { - propsData?: Record; - } - - interface RenderXEmitTestAPI> { - emit: Mock]>; - wrapper: Wrapper>; - } - - function renderXEmitTest>( - component: Component, - { propsData }: RenderXEmitTestOptions = {} - ): RenderXEmitTestAPI { - const emit = jest.fn(); - const localVue = createLocalVue(); - const wrapper = mount>(component, { - localVue, - propsData, - mocks: { - $x: { - emit - } - } - }); - - return { - wrapper, - emit - }; - } - - it('emits the provided event when a prop changes', async () => { - @Component - class PropsTest extends Vue { - @XEmit('UserAcceptedAQuery') - @Prop({ required: true }) - public someProp!: string; - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(PropsTest, { - propsData: { someProp: 'first' } - }); - - expect(emit).toHaveBeenCalledTimes(1); - expect(emit).toHaveBeenNthCalledWith(1, 'UserAcceptedAQuery', 'first'); - - await wrapper.setProps({ someProp: 'second' }); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenNthCalledWith(2, 'UserAcceptedAQuery', 'second'); - }); - - it('emits the provided event when a data property changes', async () => { - @Component - class DataPropertyTest extends Vue { - @XEmit('UserAcceptedAQuery') - public someData = 'first'; - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(DataPropertyTest); - - expect(emit).toHaveBeenCalledTimes(1); - expect(emit).toHaveBeenNthCalledWith(1, 'UserAcceptedAQuery', 'first'); - - wrapper.vm.someData = 'second'; - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenNthCalledWith(2, 'UserAcceptedAQuery', 'second'); - }); - - it('emits the provided event when a computed property changes', async () => { - @Component - class ComputedPropertyTest extends Vue { - public someData = 'first'; - - @XEmit('UserAcceptedAQuery') - public get computedProperty(): string { - return `computed: ${this.someData}`; - } - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(ComputedPropertyTest); - - expect(emit).toHaveBeenCalledTimes(1); - expect(emit).toHaveBeenNthCalledWith(1, 'UserAcceptedAQuery', 'computed: first'); - - wrapper.vm.someData = 'second'; - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenNthCalledWith(2, 'UserAcceptedAQuery', 'computed: second'); - }); - - it('clones the observed property if it is an array', async () => { - @Component - class CloningNotPrimitivesTest extends Vue { - @XEmit('SelectedFiltersChanged') - public someData = [createSimpleFilter('category', 'food')]; - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(CloningNotPrimitivesTest); - - expect(emit).toHaveBeenCalledTimes(1); - expect(emit).toHaveBeenNthCalledWith(1, 'SelectedFiltersChanged', wrapper.vm.someData); - expect(emit.mock.calls[0][1]).not.toBe(wrapper.vm.someData); - - wrapper.vm.someData = []; - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenNthCalledWith(2, 'SelectedFiltersChanged', wrapper.vm.someData); - expect(emit.mock.calls[1][1]).not.toBe(wrapper.vm.someData); - }); - - it('clones the observed property if it is an object', async () => { - @Component - class CloningNotPrimitivesTest extends Vue { - @XEmit('UserClickedAFilter') - public someData = createSimpleFilter('category', 'food'); - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(CloningNotPrimitivesTest); - - expect(emit).toHaveBeenCalledTimes(1); - expect(emit).toHaveBeenNthCalledWith(1, 'UserClickedAFilter', wrapper.vm.someData); - expect(emit.mock.calls[0][1]).not.toBe(wrapper.vm.someData); // Checking for reference equality - - wrapper.vm.someData = createSimpleFilter('category', 'beverages'); - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenNthCalledWith(2, 'UserClickedAFilter', wrapper.vm.someData); - expect(emit.mock.calls[1][1]).not.toBe(wrapper.vm.someData); // Checking for reference equality - }); - - it('allows to deep watch objects', async () => { - @Component - class CloningNotPrimitivesTest extends Vue { - @XEmit('UserClickedAHierarchicalFilter', { deep: true }) - public hierarchical = createHierarchicalFilter('category', 'food'); - - @XEmit('UserClickedASimpleFilter') - public simple = createSimpleFilter('brand', 'pepechuleton'); - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(CloningNotPrimitivesTest); - - expect(emit).toHaveBeenCalledTimes(2); - expect(emit).toHaveBeenNthCalledWith( - 1, - 'UserClickedAHierarchicalFilter', - wrapper.vm.hierarchical - ); - expect(emit).toHaveBeenNthCalledWith(2, 'UserClickedASimpleFilter', wrapper.vm.simple); - - wrapper.vm.hierarchical.selected = true; - wrapper.vm.simple.selected = true; - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(3); - expect(emit).toHaveBeenNthCalledWith( - 3, - 'UserClickedAHierarchicalFilter', - wrapper.vm.hierarchical - ); - }); - - it('allows to ignore initial value', async () => { - @Component - class CloningNotPrimitivesTest extends Vue { - @XEmit('UserClickedAFilter', { immediate: false }) - public someData = createSimpleFilter('category', 'food'); - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(CloningNotPrimitivesTest); - - expect(emit).toHaveBeenCalledTimes(0); - - wrapper.vm.someData = createSimpleFilter('category', 'beer'); - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(1); - expect(emit).toHaveBeenNthCalledWith(1, 'UserClickedAFilter', wrapper.vm.someData); - }); - - it('does not emit anything if the initial value is undefined', async () => { - @Component - class UndefinedValueTest extends Vue { - @XEmit('UserAcceptedAQuery') - @Prop() - public someProp!: string | undefined; - - render(h: CreateElement): VNode { - return h(); - } - } - - const { wrapper, emit } = renderXEmitTest(UndefinedValueTest); - - expect(emit).toHaveBeenCalledTimes(0); - - wrapper.setProps({ someProp: 'nope' }); - await wrapper.vm.$nextTick(); - expect(emit).toHaveBeenCalledTimes(0); - }); -}); diff --git a/packages/x-components/src/components/decorators/__tests__/debounce.decorators.spec.ts b/packages/x-components/src/components/decorators/__tests__/debounce.decorators.spec.ts deleted file mode 100644 index aca2275fde..0000000000 --- a/packages/x-components/src/components/decorators/__tests__/debounce.decorators.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { mount, Wrapper } from '@vue/test-utils'; -import Vue, { CreateElement, VNode } from 'vue'; -import { Component } from 'vue-property-decorator'; -import { DebounceOptions } from '../../../utils/types'; -import { Debounce } from '../debounce.decorators'; - -function renderDebounceDecoratorComponent( - debounceTime: number, - debounceOptions?: DebounceOptions -): DebounceDecoratorComponentAPI { - const mockedDebouncedFunction = jest.fn(); - - @Component - class TestingComponent extends Vue { - @Debounce(debounceTime, debounceOptions) - debounceTest(mockArgument?: any): void { - mockedDebouncedFunction(mockArgument); - } - - render(createElement: CreateElement): VNode { - return createElement(); - } - } - - const component = mount(TestingComponent); - - return { - component, - debounceTest(mockArgument?: any) { - return component.vm.debounceTest(mockArgument); - }, - mockedDebouncedFunction - }; -} - -const defaultDebounceTime = 100; - -describe('testing debounce decorator', () => { - jest.useFakeTimers(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('debounces the method for the provided time', () => { - // eslint-disable-next-line @typescript-eslint/unbound-method - const { debounceTest, mockedDebouncedFunction } = - renderDebounceDecoratorComponent(defaultDebounceTime); - - debounceTest(); - expect(mockedDebouncedFunction).not.toHaveBeenCalled(); - debounceTest(); - debounceTest(); - jest.advanceTimersByTime(defaultDebounceTime); - expect(mockedDebouncedFunction).toHaveBeenCalledTimes(1); - }); - - it('debounces the method for the provided time and options', () => { - // eslint-disable-next-line @typescript-eslint/unbound-method - const { debounceTest, mockedDebouncedFunction } = renderDebounceDecoratorComponent( - defaultDebounceTime, - { leading: true, trailing: false } - ); - - debounceTest(); - expect(mockedDebouncedFunction).toHaveBeenCalledTimes(1); - debounceTest(); - debounceTest(); - jest.advanceTimersByTime(defaultDebounceTime); - expect(mockedDebouncedFunction).toHaveBeenCalledTimes(1); - }); - - it('applies the arguments correctly to the decorated method', () => { - const mockedArgument = 'potatoe'; - // eslint-disable-next-line @typescript-eslint/unbound-method - const { debounceTest, mockedDebouncedFunction } = - renderDebounceDecoratorComponent(defaultDebounceTime); - - debounceTest(mockedArgument); - jest.advanceTimersByTime(defaultDebounceTime); - expect(mockedDebouncedFunction).toHaveBeenCalledWith(mockedArgument); - }); - - it('cancels pending debounced execution when the component is destroyed', () => { - // eslint-disable-next-line @typescript-eslint/unbound-method - const { component, debounceTest, mockedDebouncedFunction } = - renderDebounceDecoratorComponent(defaultDebounceTime); - - debounceTest(); - expect(mockedDebouncedFunction).not.toHaveBeenCalled(); - - component.destroy(); - jest.advanceTimersByTime(defaultDebounceTime); - expect(mockedDebouncedFunction).not.toHaveBeenCalled(); - }); -}); - -interface DebounceDecoratorComponentAPI { - component: Wrapper; - debounceTest(mockArgument?: any): void; - mockedDebouncedFunction(): jest.Mock; -} diff --git a/packages/x-components/src/components/decorators/__tests__/injection.decorators.spec.ts b/packages/x-components/src/components/decorators/__tests__/injection.decorators.spec.ts deleted file mode 100644 index a190f28cb8..0000000000 --- a/packages/x-components/src/components/decorators/__tests__/injection.decorators.spec.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { mount, VueClass, Wrapper } from '@vue/test-utils'; -import Vue from 'vue'; -import { Component, Prop } from 'vue-property-decorator'; -import { XInject, XProvide } from '../injection.decorators'; - -@Component({ - template: ` -
- `, - provide: { - defaultInjectWayValue: 'DefaultInjectValue' - } -}) -class Provider extends Vue { - @Prop() - @XProvide('items') - public items!: string[]; - - @Prop() - @XProvide('value') - public simpleValue!: string; - - @XInject('notProvidedKey', 'DefaultValue') - public notProvided!: string; -} - -@Component({ - template: ` -
- `, - inject: ['defaultInjectWayValue'] -}) -class FilterItems extends Vue { - public defaultInjectWayValue!: string; - - @XInject('items') - public items!: string[]; - - @XProvide('items') - public get evenItems(): string[] { - return this.items.filter((_, index) => index % 2 === 0); - } -} - -@Component({ - template: ` -
- `, - inject: ['defaultInjectWayValue'] -}) -class Child extends Vue { - public defaultInjectWayValue!: string; - - @XInject('items') - public items!: string[]; - - @XInject('value') - public simpleValue!: string; -} - -describe('testing inject decorators', () => { - function mountComponent( - { items = [] as string[], simpleValue = '' } = {}, - template = ` - - - - - ` - ): RenderInjectionComponentsAPI { - const wrapper = mount( - { - template, - components: { Provider, FilterItems, Child } - }, - { propsData: { items, simpleValue } } - ); - - return { - providerWrapper: wrapper.findComponent(Provider as VueClass), - filterItemsWrapper: wrapper.findComponent(FilterItems as VueClass), - childWrapper: wrapper.findComponent(Child as VueClass) - }; - } - - it('renders the injected values from a parent', () => { - const items = ['a', 'b', 'c']; - const simpleValue = 'Test Value'; - const { childWrapper } = mountComponent( - { - items, - simpleValue - }, - '' - ); - - expect(childWrapper.vm.items).toEqual(items); - expect(childWrapper.vm.simpleValue).toEqual(simpleValue); - }); - - it(`renders the overridden injected value from a grandparent with a component - in the middle that overrides that injection`, () => { - const items = ['a', 'b', 'c']; - const expectedItems = ['a', 'c']; - const { childWrapper } = mountComponent({ items }); - - expect(childWrapper.vm.items).toEqual(expectedItems); - }); - - it('renders the injected value even when it overrides it for the children', () => { - const items = ['a', 'b', 'c']; - const { filterItemsWrapper } = mountComponent({ items }); - - expect(filterItemsWrapper.vm.items).toEqual(items); - }); - - it(`renders an injected value provided from grandparent component with a component - in the middle that doesn't inject neither provide that value`, () => { - const simpleValue = 'Test Value'; - const { childWrapper } = mountComponent({ - simpleValue - }); - - expect(childWrapper.vm.simpleValue).toEqual(simpleValue); - }); - - it(`reacts to updates from an injected value provided by grandparent component with a component - in the middle that doesn't inject neither provide that value`, async () => { - const simpleValue = 'Test Value'; - const newSimpleValue = 'New Test Value'; - const { childWrapper, providerWrapper } = mountComponent({ - simpleValue - }); - - expect(childWrapper.vm.simpleValue).toEqual(simpleValue); - await providerWrapper.setProps({ simpleValue: newSimpleValue }); - expect(childWrapper.vm.simpleValue).toEqual(newSimpleValue); - }); - - it(`reacts to updates from an injected value provided by grandparent component with a component - in the middle that overrides that injection`, async () => { - const items = ['a', 'b', 'c', 'd']; - const expectedItems = ['a', 'c']; - const newItems = ['1', '2', '3', '4', '5']; - const newExpectedItems = ['1', '3', '5']; - const { childWrapper, providerWrapper } = mountComponent({ - items - }); - - expect(childWrapper.vm.items).toEqual(expectedItems); - await providerWrapper.setProps({ items: newItems }); - expect(childWrapper.vm.items).toEqual(newExpectedItems); - }); - - it('keeps the default injection working', () => { - const { filterItemsWrapper, childWrapper } = mountComponent({ - items: ['a', 'b', 'c', 'd'], - simpleValue: 'SimpleValue' - }); - expect(filterItemsWrapper.vm.defaultInjectWayValue).toEqual('DefaultInjectValue'); - expect(childWrapper.vm.defaultInjectWayValue).toEqual('DefaultInjectValue'); - }); - - it('injects default value if the inject key is not provided', () => { - const { providerWrapper } = mountComponent({}, ''); - expect(providerWrapper.vm.notProvided).toEqual('DefaultValue'); - }); -}); - -interface RenderInjectionComponentsAPI { - providerWrapper: Wrapper; - filterItemsWrapper: Wrapper; - childWrapper: Wrapper; -} diff --git a/packages/x-components/src/components/decorators/__tests__/store.decorators.spec.ts b/packages/x-components/src/components/decorators/__tests__/store.decorators.spec.ts deleted file mode 100644 index ea2cc911cb..0000000000 --- a/packages/x-components/src/components/decorators/__tests__/store.decorators.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { createLocalVue, mount, Wrapper } from '@vue/test-utils'; -import Vue, { CreateElement, VNode } from 'vue'; -import { Component } from 'vue-property-decorator'; -import Vuex, { Store } from 'vuex'; -import { installNewXPlugin } from '../../../__tests__/utils'; -import { searchBoxXStoreModule } from '../../../x-modules/search-box/store/module'; -import { searchBoxXModule } from '../../../x-modules/search-box/x-module'; -import { xComponentMixin } from '../../x-component.mixin'; -import { Getter, State } from '../store.decorators'; - -@Component({ - mixins: [xComponentMixin(searchBoxXModule)] -}) -class TestingComponent extends Vue { - @State('searchBox', 'query') - public query!: string; - @Getter('searchBox', 'trimmedQuery') - public trimmedQuery!: string; - - render(createElement: CreateElement): VNode { - return createElement(); - } -} - -describe('testing store decorators', () => { - let component: Wrapper; - - beforeEach(() => { - component?.vm.$destroy(); - jest.clearAllMocks(); - const localVue = createLocalVue(); - localVue.use(Vuex); - const store = new Store({ - modules: { - x: { - namespaced: true, - modules: { - searchBox: { namespaced: true, ...searchBoxXStoreModule } as any - } - } - } - }); - installNewXPlugin({}, localVue); - - component = mount(TestingComponent, { - localVue, - store - }); - }); - - it('maps store state', () => { - expect(component.vm.query).toEqual(''); - - component.vm.$store.commit('x/searchBox/setQuery', 'pork shoulder '); - - expect(component.vm.query).toEqual('pork shoulder '); - }); - - it('maps store getters', () => { - expect(component.vm.trimmedQuery).toEqual(''); - - component.vm.$store.commit('x/searchBox/setQuery', 'short ribs '); - - expect(component.vm.trimmedQuery).toEqual('short ribs'); - }); -}); diff --git a/packages/x-components/src/components/decorators/bus.decorators.ts b/packages/x-components/src/components/decorators/bus.decorators.ts deleted file mode 100644 index aaa99bc52d..0000000000 --- a/packages/x-components/src/components/decorators/bus.decorators.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { AnyFunction } from '@empathyco/x-utils'; -import { Observable, Subscription } from 'rxjs'; -import { filter } from 'rxjs/operators'; -import Vue, { WatchOptions } from 'vue'; -import { createDecorator } from 'vue-class-component'; -import { EventPayload, SubjectPayload } from '@empathyco/x-bus'; -import { clone } from '../../utils/clone'; -import { DecoratorFor } from '../../utils/types'; -import { XEvent, XEventPayload, XEventsTypes } from '../../wiring/events.types'; -import { WireMetadata } from '../../wiring/wiring.types'; - -/** - * Creates a subscription to an {@link XEvent}, an array of {@link XEvent} or a component property ( - * reacting to its changes via a watcher) filtering out the passed metadata, if any, and - * un-subscribes on the beforeDestroy hook. - * - * @remarks - * The decorated property needs to be public for type inference to work. - * - * @param xEvent - The {@link XEvent}, an array of {@link XEvent} or a component property. - * @param metadataFilteringOptions - The {@link WireMetadata} options to filter out a callback - * execution. - * @returns Decorator that creates a subscription to an {@link XEvent} and un-subscribes on the - * beforeDestroy hook. - * - * @public - * @deprecated Use {@link useXBus} composable instead. - */ -export function XOn( - xEvent: Event | Event[] | ((component: Vue) => Event | Event[]), - metadataFilteringOptions: Partial = {} -): DecoratorFor<(payload: XEventPayload, metadata: WireMetadata) => void> { - return createDecorator((options, key) => { - // eslint-disable-next-line @typescript-eslint/unbound-method - const originalCreated = options.created; - Object.assign(options, { - created(this: Vue) { - originalCreated?.apply(this); - const componentCreateSubscription = createSubscription.bind(this); - const subscriptionMetadata: SubscriptionMetadata = { - event: [], - callback: (this as any)[key], // `this` isn't correctly typed here - metadataFilteringOptions - }; - - let subscription: Subscription; - if (typeof xEvent === 'function') { - this.$watch( - () => xEvent(this), - newEvents => { - subscription?.unsubscribe(); - subscriptionMetadata.event = newEvents; - subscription = componentCreateSubscription(subscriptionMetadata); - }, - { immediate: true } - ); - } else { - subscriptionMetadata.event = xEvent; - subscription = componentCreateSubscription(subscriptionMetadata); - } - - this.$on('hook:beforeDestroy', () => subscription.unsubscribe()); // Using Vue - // bus to subscribe to the lifecycle hook 'beforeDestroy' instead of 'capturing' the - // original component's 'beforeDestroy' method to override it plus calling - // originalBeforeDestroy.apply(this) to preserve the existing original hook functionality - } - }); - }); -} - -/** - * Create a subscription for the given events executing the passed callback and filtering out based - * on the passed metadata options. - * - * @param this - The vue component. - * @param subscriptionMetadata - The {@link SubscriptionMetadata}. - * @returns A - * {@link https://www.learnrxjs.io/learn-rxjs/concepts/rxjs-primer#subscription | subscription}. - * @internal - */ -function createSubscription( - this: Vue, - subscriptionMetadata: SubscriptionMetadata -): Subscription { - const { event, callback, metadataFilteringOptions } = subscriptionMetadata; - const eventArray = Array.isArray(event) ? event : [event]; - const subscription = new Subscription(); - eventArray.forEach(xEvent => { - subscription.add( - ( - this.$x.on(xEvent, true) as unknown as Observable< - SubjectPayload, WireMetadata> - > - ) - .pipe(filter(({ metadata }) => filterMetadataOptions(metadataFilteringOptions, metadata))) - .subscribe(({ eventPayload, metadata }) => callback(eventPayload, metadata)) - ); - }); - return subscription; -} - -/** - * Checks if the metadata options passed to the decorator match the metadata of the emitted event. - * - * @param filteringOptions - The decorator options. - * @param eventOptions - The emitted event metadata. - * @returns True if options are empty or match the metadata. - * @internal - */ -function filterMetadataOptions( - filteringOptions: Partial, - eventOptions: WireMetadata -): boolean { - return (Object.keys(filteringOptions) as WireMetadataKey[]) - .filter(key => filteringOptions[key] !== undefined) - .every(key => filteringOptions[key] === eventOptions[key]); -} - -/** - * The subscription metadata containing an/a list of {@link XEvent}, the callback function to - * execute and the metadataOptions to filter out the execution of the callback. - * - * @internal - */ -interface SubscriptionMetadata { - /** - * An {@link XEvent} or a list of them. - */ - event: Event | Event[]; - /** - * A callback function to execute in the subscription. - */ - callback: AnyFunction; - /** - * The metadataFilteringOptions to filter out the execution of the callback. - */ - metadataFilteringOptions: Partial; -} - -/** - * Emits the provided event whenever the decorated property changes. - * - * @param xEvent - The event to emit. - * @param watcherOptions - Options for Vue's watcher. - * @returns Decorator that makes the component emit an event when the decorated property changes. - * - * @public - * @deprecated Use {@link useXBus} composable instead. - */ -export function XEmit( - xEvent: Event, - { immediate = true, deep = false }: WatchOptions = {} -): DecoratorFor | undefined> { - return createDecorator((options, key) => { - // eslint-disable-next-line @typescript-eslint/unbound-method - const originalCreated = options.created; - options.created = function (this: Vue) { - originalCreated?.apply(this); - if ((this as any)[key] !== undefined) { - this.$watch( - key, - newValue => { - this.$x.emit( - xEvent, - typeof newValue === 'object' && newValue !== null ? clone(newValue) : newValue - ); - }, - { immediate, deep } - ); - } - }; - }); -} diff --git a/packages/x-components/src/components/decorators/debounce.decorators.ts b/packages/x-components/src/components/decorators/debounce.decorators.ts deleted file mode 100644 index b7f951a25d..0000000000 --- a/packages/x-components/src/components/decorators/debounce.decorators.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { AnyFunction } from '@empathyco/x-utils'; -import { createDecorator } from 'vue-class-component'; -import { debounce } from '../../utils/debounce'; -import { DebounceOptions, DecoratorFor } from '../../utils/types'; - -/** - * Adds debounce to the method that the decorator is applied to. - * - * @remarks Pending debounced execution is cancelled when the component is destroyed. - * - * @param debounceTimeInMs - The time of debounce in ms. - * @param debounceOptions - The options for the debounce strategy. - * - * @returns Decorator that applies debounce. - * - * @public - * @deprecated Use {@link useDebounce} composable instead. - */ -export function Debounce( - debounceTimeInMs: number, - debounceOptions: DebounceOptions = {} -): DecoratorFor { - return createDecorator((options, key) => { - const originalMethod = options.methods![key]; - const debouncedMethod = debounce( - (context: Vue, args: unknown[]) => originalMethod.call(context, ...args), - debounceTimeInMs, - debounceOptions - ); - - options.methods![key] = function debouncedWrapper(...args: unknown[]) { - debouncedMethod(this, args); - }; - - // eslint-disable-next-line @typescript-eslint/unbound-method - const originalBeforeDestroy = options.beforeDestroy; - Object.assign(options, { - beforeDestroy(this: Vue) { - originalBeforeDestroy?.apply(this); - debouncedMethod.cancel(); - } - }); - }); -} diff --git a/packages/x-components/src/components/decorators/injection.consts.ts b/packages/x-components/src/components/decorators/injection.consts.ts index 91207af292..e5adfc14e1 100644 --- a/packages/x-components/src/components/decorators/injection.consts.ts +++ b/packages/x-components/src/components/decorators/injection.consts.ts @@ -1,6 +1,18 @@ import { Result, ResultVariant } from '@empathyco/x-types'; import { ListItem } from '../../utils/types'; -import { XInjectKey } from './injection.decorators'; + +/** + * Type of the key passed to {@link XProvide} and {@link XInject} to be type-safe. With this type + * you can declare the type of the injected value directly in the injection key. + * + * @example + * `const myKey: XInjectKey = 'myFilter';` + * `@XInject(myKey)` + * + * @public + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export interface XInjectKey extends String {} /** * It's used to identify the provided and injected `disable-animations`. diff --git a/packages/x-components/src/components/decorators/injection.decorators.ts b/packages/x-components/src/components/decorators/injection.decorators.ts deleted file mode 100644 index 30bec45210..0000000000 --- a/packages/x-components/src/components/decorators/injection.decorators.ts +++ /dev/null @@ -1,254 +0,0 @@ -import Vue, { ComponentOptions } from 'vue'; -import { createDecorator } from 'vue-class-component'; -import { arrayToObject } from '../../utils/array'; -import { DecoratorFor } from '../../utils/types'; - -/** - * The type of the Vue Component provide configuration, narrowed to the object type. - * - * @internal - */ -// eslint-disable-next-line @typescript-eslint/ban-types -type ProvideObjectConfig = Exclude['provide'], (() => object) | undefined>; - -/** - * The type of the Vue Component inject configuration, narrowed to the object type. - * - * @internal - */ -type InjectObjectConfig = Exclude['inject'], string[] | undefined>; - -/** - * Type of the key passed to {@link XProvide} and {@link XInject} to be type-safe. With this type - * you can declare the type of the injected value directly in the injection key. - * - * @example - * `const myKey: XInjectKey = 'myFilter';` - * `@XInject(myKey)` - * - * @public - */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export interface XInjectKey extends String {} - -/** - * The union type for the different functions in this module. - * - * @internal - */ -type AnyInjectKey = XInjectKey | string; - -/** - * Generates a provide function that returns an object with the injectable value returned in a - * getter to keep its reactivity, using the default - * {@link https://vuejs.org/v2/api/#provide-inject | Vue inject}. It overrides the provide key if - * the parent provides the same key. - * - * @remarks The decorated property needs to be public for type inference to work. - * - * @param provideKey - The key used to provide. This key can be a 'string' or a 'XInject'. - * This last type is to support type-safe injection. When this decorator is used, it is possible - * to specify the type of the injected value. Take a look to the example below. - * @returns Decorator with the provide configuration. - * - * @example - * Type unsafe injection (but allowed): - * \@XProvide('myKey') - * - * Type safe injection (recommended): - * const myKey: XInjectKey = 'myKey'; - * \@XProvide(myKey) - * - * This last one, you are specifying that the injected value with the key 'myKey' has the Date - * type. - * - * @public - * @deprecated Use native Vue `provide` instead. - */ -export function XProvide(provideKey: AnyInjectKey): DecoratorFor { - return createDecorator((options, componentKey) => { - const previousProvide = options.provide; - options.provide = function (this: ComponentInstance) { - const previousProvideObject = getPreviousProvideObject(previousProvide, this); - const newProvideObject = getNewProvideObject(provideKey, componentKey, this); - return Object.assign(previousProvideObject, newProvideObject); - }; - }); -} - -/** - * Generates an inject configuration object to inject a value provided by {@link XProvide}. - * This function injects the value into a private property of the component instance using the - * default {@link https://vuejs.org/v2/api/#provide-inject | Vue inject}. This private property - * is named as the decorated property but prefixed with `_x-inject_`. - * - * Why is this private property necessary? Well, the {@link XProvide} decorator, provides an object - * with the shape \{ value: any \} being that value a getter to keep reactivity of the injected - * value. This private property is to "shortcut" that object and directly inject the value itself. - * Otherwise, you should access to the actual value using `.value`. - * - * The final step is done by a computed property. This has the same name as the decorated property. - * This computed returns the inner value getter of the injected object. This way the decorated - * property has finally the initial injected value. - * - * @remarks The decorated property needs to be public for type inference to work. - * - * @param injectKey - The key used to inject. This key can be a 'string' or a 'XInject'. - * This last type is to support type-safe injection. When this decorator is used, it is possible - * to specify the type of the injected value. Take a look to the example below. - * @returns Decorator with the provide configuration. - * - * @param defaultValue - The default value to use if there is not value provided. - * - * @example - * Type unsafe injection (but allowed): - * \@XInject('myKey') - * - * Type safe injection (recommended): - * const myKey: XInjectKey = 'myKey'; - * \@XInject(myKey) - * - * @public - * @deprecated Use native Vue `inject` instead. - */ -export function XInject( - injectKey: AnyInjectKey, - defaultValue?: Type -): DecoratorFor { - return createDecorator((options, componentKey) => { - const privateComponentKey = `_x-inject_${componentKey}`; - const previousInjectObject = getPreviousInjectObject(options.inject); - const newInjectObject = getNewInjectObject(injectKey, privateComponentKey, defaultValue); - options.inject = Object.assign(previousInjectObject, newInjectObject); - const computedToPrivateProperty = getComputedProperty(componentKey, privateComponentKey); - options.computed = Object.assign(options.computed ?? {}, computedToPrivateProperty); - }); -} - -/** - * This function receives the previous provide of the component instance. - * If the provide is a function, then returns it as an object invoking it with the component - * instance. - * If the provide is an object then it is returned directly. - * If the provide is undefined, then an empty object returned. - * - * @param previousProvide - The {@link ComponentOptions.provide } configuration that exist before - * applying this decorator. - * @param componentInstance - A Vue Component instance to invoke the provide function. - * - * @returns {@link ProvideObjectConfig} With the provide configuration as an object. - */ -function getPreviousProvideObject( - previousProvide: ComponentOptions['provide'], - componentInstance: ComponentInstance -): ProvideObjectConfig { - if (isProvideFunction(previousProvide)) { - return previousProvide.call(componentInstance); - } else { - return previousProvide ?? {}; - } -} - -/** - * This function creates a new provide configuration, wrapping the value to provide inside a getter - * called `value`. This is done to keep the reactivity of the injected value. - * - * @param provideKey - The key of the provide value. - * @param componentKey - The name of the property decorated with {@link XProvide}. - * @param componentInstance - The {@link Vue} instance of the component to invoke the provide - * function. - * - * @returns {@link ProvideObjectConfig} The object with the key of the provideKey and the `value` - * getter. - */ -function getNewProvideObject( - provideKey: AnyInjectKey, - componentKey: string, - componentInstance: ComponentInstance -): ProvideObjectConfig { - return { - [provideKey as string]: { - get value() { - return componentInstance[componentKey as keyof ComponentInstance]; - } - } - }; -} - -/** - * This function returns the previous inject config as an object. This will be used to merge it with - * the new inject configuration. - * If the previous inject config of the component instance is an Array, then it converts it into an - * object. - * If the previous inject config of the component instance is an object, then it returns it - * directly. - * If the previous inject config of the component instance is undefined, then an empty object is - * returned. - * - * @param previousInject - The previous inject configuration of the component instance. - * - * @returns {@link InjectObjectConfig} The object with the previous inject config in form of object. - */ -function getPreviousInjectObject( - previousInject: ComponentOptions['inject'] -): InjectObjectConfig { - if (Array.isArray(previousInject)) { - return arrayToObject(previousInject); - } else { - return previousInject ?? {}; - } -} - -/** - * This function returns the new inject configuration. This will be merged with the previous inject - * configuration. - * It returns an object with the key and a string if no `defaultValue` is passed. Otherwise it - * returns an object with `from` and `default` keys. - * - * @param injectKey - The key of the injected value. - * @param componentKey - The name of the component key where the value will be injected. - * @param defaultValue - The default value of the injection if the `injectKey` has no provide. - * - * @returns The object with the inject configuration. - */ -function getNewInjectObject( - injectKey: AnyInjectKey, - componentKey: string, - defaultValue?: DefaultValue -): InjectObjectConfig { - return { [componentKey]: { from: injectKey as string, default: { value: defaultValue } } }; -} - -/** - * This function returns the computed configuration for bypass the `value` of the provide - * of {@link XProvide}. This will be used to override the property decorated with {@link XInject} - * with the computed. - * - * @param computedKey - The key used for the computed. - * @param privateComponentKey - The "private" component property where the value is actually - * injected. - * - * @returns The computed config to assign/merge with the component options. - */ -function getComputedProperty( - computedKey: string, - privateComponentKey: string -): ComponentOptions['computed'] { - return { - [computedKey]: function (): unknown { - return (this as unknown as Record)[privateComponentKey].value; - } - }; -} - -/** - * Type guard to check if a provide configuration is a function. - * - * @param provide - The provide configuration. - * @returns A boolean indicating if the passed provide is a function. - */ -function isProvideFunction( - provide: ComponentOptions['provide'] -): provide is (this: Vue) => ProvideObjectConfig { - return typeof provide === 'function'; -} diff --git a/packages/x-components/src/components/decorators/store.decorators.ts b/packages/x-components/src/components/decorators/store.decorators.ts deleted file mode 100644 index 91f3810b45..0000000000 --- a/packages/x-components/src/components/decorators/store.decorators.ts +++ /dev/null @@ -1,62 +0,0 @@ -import Vue, { ComponentOptions } from 'vue'; -import { createDecorator } from 'vue-class-component'; -import { getGetterPath } from '../../plugins/x-plugin.utils'; -import { DecoratorFor } from '../../utils/index'; -import { ExtractGetters, ExtractState, XModuleName } from '../../x-modules/x-modules.types'; - -/** - * Generates a computed property which returns the selected state. - * - * The decorated property needs to be public for type inference to work. - * - * @param module - The {@link XModuleName} of the getter. - * @param path - The state path. - * @returns Decorator with the state properties of the module. - * - * @public - * @deprecated Use {@link useState} composable instead. - */ -export function State>( - module: Module, - path: Path -): DecoratorFor[Path]> { - return createDecorator((options, key) => { - if (!options.computed) { - options.computed = {}; - } - Object.assign(options.computed, { - [key]() { - return this.$store.state.x[module][path]; - } - } as ThisType); - }); -} - -/** - * Generates a computed property which returns the selected getter value. - * - * The decorated property needs to be public for type inference to work. - * - * @param module - The {@link XModuleName} of the getter. - * @param getter - The getter name. - * @returns Decorator with the getters of the module. - * - * @public - * @deprecated Use {@link useGetter} composable instead. - */ -export function Getter>( - module: Module, - getter: GetterName -): DecoratorFor[GetterName]> { - return createDecorator((options: ComponentOptions, key: string) => { - if (!options.computed) { - options.computed = {}; - } - const getterPath = getGetterPath(module, getter); - Object.assign(options.computed, { - [key]() { - return this.$store.getters[getterPath]; - } - } as ThisType); - }); -} diff --git a/packages/x-components/src/x-installer/x-installer/types.ts b/packages/x-components/src/x-installer/x-installer/types.ts index 446f81cca9..9d308b8492 100644 --- a/packages/x-components/src/x-installer/x-installer/types.ts +++ b/packages/x-components/src/x-installer/x-installer/types.ts @@ -40,21 +40,6 @@ export interface InstallXOptions extends XPluginOptions * installed. */ plugin?: Plugin; - /** - * This object can contain any option to pass to Vue instance at the moment of creating the App - * instance. - * - * @example - * ```typescript - * { - * vueOptions:{ - * i18n, - * router - * } - * } - * ``` - */ - vueOptions?: VueConstructorPartialArgument; /** * Callback to invoke after instantiating the app. @@ -90,13 +75,6 @@ export interface ExtraPluginsOptions { snippet: NormalisedSnippetConfig; } -/** - * First parameter of the Vue constructor. - * - * @public - */ -export type VueConstructorPartialArgument = Partial>; - /** * Interface for the returned type of the {@link XInstaller.(init:1)} function. * diff --git a/packages/x-components/src/x-installer/x-installer/x-installer.ts b/packages/x-components/src/x-installer/x-installer/x-installer.ts index c750762d59..d2e45aa674 100644 --- a/packages/x-components/src/x-installer/x-installer/x-installer.ts +++ b/packages/x-components/src/x-installer/x-installer/x-installer.ts @@ -7,7 +7,7 @@ import { NormalisedSnippetConfig, SnippetConfig, XAPI } from '../api/api.types'; import { BaseXAPI } from '../api/base-api'; import { WireMetadata, XEventsTypes } from '../../wiring/index'; import { bus } from '../../plugins/x-bus'; -import { InitWrapper, InstallXOptions, VueConstructorPartialArgument } from './types'; +import { InitWrapper, InstallXOptions } from './types'; declare global { interface Window { @@ -164,7 +164,7 @@ export class XInstaller { async init(snippetConfig = this.retrieveSnippetConfig()): Promise { if (snippetConfig) { this.snippetConfig = reactive(this.normaliseSnippetConfig(snippetConfig)); - this.createApp({}); + this.createApp(); const bus = this.createBus(); const pluginOptions = this.getPluginOptions(); const plugin = this.installPlugin(pluginOptions, bus); @@ -269,20 +269,12 @@ export class XInstaller { * In the case that the `rootComponent` parameter is present in the {@link InstallXOptions}, then a new Vue * application is created using that component as root. * - * @param extraPlugins - Vue plugins initialisation data. - * * @internal */ - protected createApp(extraPlugins: VueConstructorPartialArgument): void { + protected createApp(): void { if (!this.options.app && this.options.rootComponent !== undefined) { - this.app = createApp(this.options.rootComponent, { - ...extraPlugins, - ...this.options.vueOptions, - provide: { - snippetConfig: this.snippetConfig - }, - store: this.options.store - }); + this.app = createApp(this.options.rootComponent); + this.app.provide('snippetConfig', this.snippetConfig); this.options.onCreateApp?.(this.app); } } diff --git a/packages/x-components/src/x-modules/experience-controls/store/module.ts b/packages/x-components/src/x-modules/experience-controls/store/module.ts index 353f1ece59..8c3475399e 100644 --- a/packages/x-components/src/x-modules/experience-controls/store/module.ts +++ b/packages/x-components/src/x-modules/experience-controls/store/module.ts @@ -26,10 +26,10 @@ export const experienceControlsXStoreModule: ExperienceControlsXStoreModule = { }, mutations: { setControls(state, controls) { - state['controls'] = controls; + state.controls = controls; }, setEvents(state, events) { - state['events'] = events; + state.events = events; }, setParams(state, params) { state.params = params; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e732806901..bd89679442 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -478,7 +478,7 @@ importers: specifier: ~2.2.0 version: 2.2.0(esbuild@0.20.0) '@empathyco/x-tailwindcss': - specifier: ^1.2.0-alpha.2 + specifier: ^1.2.0-alpha.3 version: link:../x-tailwindcss '@microsoft/api-documenter': specifier: ~7.23.0 @@ -508,8 +508,8 @@ importers: specifier: ~5.14.5 version: 5.14.5 '@vitejs/plugin-vue': - specifier: ^5.0.4 - version: 5.0.4(vite@4.5.0)(vue@3.4.31) + specifier: ~5.0.5 + version: 5.0.5(vite@4.5.0)(vue@3.4.31) '@vue/test-utils': specifier: ~2.4.6 version: 2.4.6 @@ -586,7 +586,7 @@ importers: specifier: ^4.5.0 version: 4.5.0(@types/node@18.19.3)(sass@1.70.0) vite-plugin-vue-inspector: - specifier: ^5.1.2 + specifier: ~5.1.2 version: 5.1.2(vite@4.5.0) vue: specifier: ~3.4.31 @@ -895,7 +895,7 @@ packages: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.3 + '@babel/types': 7.24.9 dev: true /@babel/helper-compilation-targets@7.22.15: @@ -990,7 +990,7 @@ packages: '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 dev: true /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3): @@ -1004,7 +1004,7 @@ packages: '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 dev: true /@babel/helper-optimise-call-expression@7.22.5: @@ -1061,21 +1061,13 @@ packages: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.3 + '@babel/types': 7.24.9 dev: true - /@babel/helper-string-parser@7.22.5: - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} - engines: {node: '>=6.9.0'} - /@babel/helper-string-parser@7.24.8: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} @@ -1091,7 +1083,7 @@ packages: dependencies: '@babel/template': 7.22.15 '@babel/traverse': 7.23.3 - '@babel/types': 7.23.3 + '@babel/types': 7.24.9 transitivePeerDependencies: - supports-color dev: true @@ -1634,8 +1626,8 @@ packages: resolution: {integrity: sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 /@babel/types@7.24.9: @@ -4524,8 +4516,8 @@ packages: vue: 3.4.22(typescript@4.9.4) dev: true - /@vitejs/plugin-vue@5.0.4(vite@4.5.0)(vue@3.4.31): - resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==} + /@vitejs/plugin-vue@5.0.5(vite@4.5.0)(vue@3.4.31): + resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: vite: ^5.0.0 @@ -4572,7 +4564,7 @@ packages: '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.3) '@babel/template': 7.22.15 '@babel/traverse': 7.23.3 - '@babel/types': 7.23.3 + '@babel/types': 7.24.9 '@vue/babel-helper-vue-transform-on': 1.1.5 camelcase: 6.3.0 html-tags: 3.3.1 @@ -16561,7 +16553,7 @@ packages: '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.3) '@vue/compiler-dom': 3.4.31 kolorist: 1.8.0 - magic-string: 0.30.9 + magic-string: 0.30.10 vite: 4.5.0(@types/node@18.19.3)(sass@1.70.0) transitivePeerDependencies: - supports-color