vue-context-storage 0.1.1 → 0.1.3
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.
- package/README.md +17 -20
- package/dist/handlers/query/index.d.cts +3 -3
- package/dist/handlers/query/index.d.ts +3 -3
- package/dist/handlers/query/transform-helpers.d.cts +1 -1
- package/dist/handlers/query/transform-helpers.d.ts +1 -1
- package/dist/handlers/query/types.d.cts +1 -1
- package/dist/handlers/query/types.d.ts +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ContextStorageCollection.vue +2 -1
- package/src/components.ts +1 -1
- package/src/handlers/query/index.ts +4 -4
- package/src/handlers/query/transform-helpers.ts +1 -1
- package/src/handlers/query/types.ts +1 -1
- package/src/index.ts +3 -3
- package/src/plugin.ts +2 -2
- /package/src/components/{ContextStorageRoot.vue → ContextStorage.vue} +0 -0
package/README.md
CHANGED
|
@@ -47,9 +47,9 @@ Then use components without importing:
|
|
|
47
47
|
|
|
48
48
|
```vue
|
|
49
49
|
<template>
|
|
50
|
-
<
|
|
50
|
+
<ContextStorage>
|
|
51
51
|
<router-view />
|
|
52
|
-
</
|
|
52
|
+
</ContextStorage>
|
|
53
53
|
</template>
|
|
54
54
|
```
|
|
55
55
|
|
|
@@ -59,13 +59,13 @@ Import components individually when needed:
|
|
|
59
59
|
|
|
60
60
|
```vue
|
|
61
61
|
<template>
|
|
62
|
-
<
|
|
62
|
+
<ContextStorage>
|
|
63
63
|
<router-view />
|
|
64
|
-
</
|
|
64
|
+
</ContextStorage>
|
|
65
65
|
</template>
|
|
66
66
|
|
|
67
67
|
<script setup lang="ts">
|
|
68
|
-
import {
|
|
68
|
+
import { ContextStorage } from 'vue-context-storage/components'
|
|
69
69
|
</script>
|
|
70
70
|
```
|
|
71
71
|
|
|
@@ -87,12 +87,12 @@ interface Filters {
|
|
|
87
87
|
const filters = ref<Filters>({
|
|
88
88
|
search: '',
|
|
89
89
|
status: 'active',
|
|
90
|
-
page: 1
|
|
90
|
+
page: 1,
|
|
91
91
|
})
|
|
92
92
|
|
|
93
93
|
// Automatically syncs filters with URL query
|
|
94
94
|
useContextStorageQueryHandler(filters, {
|
|
95
|
-
prefix: 'filters' // URL will be: ?filters[search]=...&filters[status]=...
|
|
95
|
+
prefix: 'filters', // URL will be: ?filters[search]=...&filters[status]=...
|
|
96
96
|
})
|
|
97
97
|
</script>
|
|
98
98
|
```
|
|
@@ -116,7 +116,7 @@ interface TableState {
|
|
|
116
116
|
const state = ref<TableState>({
|
|
117
117
|
page: 1,
|
|
118
118
|
search: '',
|
|
119
|
-
perPage: 25
|
|
119
|
+
perPage: 25,
|
|
120
120
|
})
|
|
121
121
|
|
|
122
122
|
useContextStorageQueryHandler(state, {
|
|
@@ -124,8 +124,8 @@ useContextStorageQueryHandler(state, {
|
|
|
124
124
|
transform: (deserialized, initial) => ({
|
|
125
125
|
page: asNumber(deserialized.page, { fallback: 1 }),
|
|
126
126
|
search: asString(deserialized.search, { fallback: '' }),
|
|
127
|
-
perPage: asNumber(deserialized.perPage, { fallback: 25 })
|
|
128
|
-
})
|
|
127
|
+
perPage: asNumber(deserialized.perPage, { fallback: 25 }),
|
|
128
|
+
}),
|
|
129
129
|
})
|
|
130
130
|
```
|
|
131
131
|
|
|
@@ -144,7 +144,7 @@ Keep empty state in URL to prevent resetting on reload:
|
|
|
144
144
|
```typescript
|
|
145
145
|
useContextStorageQueryHandler(filters, {
|
|
146
146
|
prefix: 'filters',
|
|
147
|
-
preserveEmptyState: true
|
|
147
|
+
preserveEmptyState: true,
|
|
148
148
|
// Empty filters will show as: ?filters
|
|
149
149
|
// Without this option, empty filters would clear the URL completely
|
|
150
150
|
})
|
|
@@ -157,14 +157,11 @@ Customize global behavior:
|
|
|
157
157
|
```typescript
|
|
158
158
|
import { ContextStorageQueryHandler } from 'vue-context-storage'
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
ContextStorageQueryHandler.configure({
|
|
161
161
|
mode: 'push', // 'replace' (default) or 'push' for history
|
|
162
162
|
preserveUnusedKeys: true, // Keep other query params
|
|
163
|
-
preserveEmptyState: false
|
|
163
|
+
preserveEmptyState: false,
|
|
164
164
|
})
|
|
165
|
-
|
|
166
|
-
// Use in ContextStorageRoot
|
|
167
|
-
<ContextStorageRoot :handlers="[CustomQueryHandler]">
|
|
168
165
|
```
|
|
169
166
|
|
|
170
167
|
## API Reference
|
|
@@ -206,7 +203,7 @@ All transform helpers support nullable and missable options:
|
|
|
206
203
|
asNumber(value, {
|
|
207
204
|
fallback: 0, // Default value
|
|
208
205
|
nullable: false, // Allow null return
|
|
209
|
-
missable: false // Allow undefined return
|
|
206
|
+
missable: false, // Allow undefined return
|
|
210
207
|
})
|
|
211
208
|
```
|
|
212
209
|
|
|
@@ -220,7 +217,7 @@ import type {
|
|
|
220
217
|
ContextStorageHandlerConstructor,
|
|
221
218
|
IContextStorageQueryHandler,
|
|
222
219
|
QueryValue,
|
|
223
|
-
SerializeOptions
|
|
220
|
+
SerializeOptions,
|
|
224
221
|
} from 'vue-context-storage'
|
|
225
222
|
```
|
|
226
223
|
|
|
@@ -235,7 +232,7 @@ import { useContextStorageQueryHandler, asNumber } from 'vue-context-storage'
|
|
|
235
232
|
const pagination = ref({
|
|
236
233
|
page: 1,
|
|
237
234
|
perPage: 25,
|
|
238
|
-
total: 0
|
|
235
|
+
total: 0,
|
|
239
236
|
})
|
|
240
237
|
|
|
241
238
|
useContextStorageQueryHandler(pagination, {
|
|
@@ -243,7 +240,7 @@ useContextStorageQueryHandler(pagination, {
|
|
|
243
240
|
transform: (data, initial) => ({
|
|
244
241
|
page: asNumber(data.page, { fallback: 1 }),
|
|
245
242
|
perPage: asNumber(data.perPage, { fallback: 25 }),
|
|
246
|
-
total: initial.total // Don't sync total from URL
|
|
243
|
+
total: initial.total, // Don't sync total from URL
|
|
247
244
|
})
|
|
248
245
|
})
|
|
249
246
|
```
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ContextStorageHandlerConstructor } from '../../handlers
|
|
2
|
-
import { contextStorageQueryHandler } from '../../symbols
|
|
1
|
+
import { ContextStorageHandlerConstructor } from '../../handlers';
|
|
2
|
+
import { contextStorageQueryHandler } from '../../symbols';
|
|
3
3
|
import { MaybeRefOrGetter } from 'vue';
|
|
4
4
|
import { LocationQuery } from 'vue-router';
|
|
5
|
-
import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types
|
|
5
|
+
import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types';
|
|
6
6
|
export declare function useContextStorageQueryHandler<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options?: RegisterQueryHandlerBaseOptions<T>): void;
|
|
7
7
|
export declare class ContextStorageQueryHandler implements IContextStorageQueryHandler {
|
|
8
8
|
#private;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ContextStorageHandlerConstructor } from '../../handlers
|
|
2
|
-
import { contextStorageQueryHandler } from '../../symbols
|
|
1
|
+
import { ContextStorageHandlerConstructor } from '../../handlers';
|
|
2
|
+
import { contextStorageQueryHandler } from '../../symbols';
|
|
3
3
|
import { MaybeRefOrGetter } from 'vue';
|
|
4
4
|
import { LocationQuery } from 'vue-router';
|
|
5
|
-
import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types
|
|
5
|
+
import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types';
|
|
6
6
|
export declare function useContextStorageQueryHandler<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options?: RegisterQueryHandlerBaseOptions<T>): void;
|
|
7
7
|
export declare class ContextStorageQueryHandler implements IContextStorageQueryHandler {
|
|
8
8
|
#private;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LocationQueryValue } from 'vue-router';
|
|
2
2
|
import { MaybeRefOrGetter, UnwrapNestedRefs, WatchHandle } from 'vue';
|
|
3
|
-
import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers
|
|
3
|
+
import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers';
|
|
4
4
|
export type QueryValue = LocationQueryValue | LocationQueryValue[];
|
|
5
5
|
export type DeepTransformValuesToLocationQueryValue<T> = {
|
|
6
6
|
[K in keyof T]?: T[K] extends object ? T[K] extends Array<any> ? QueryValue : DeepTransformValuesToLocationQueryValue<T[K]> : QueryValue;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LocationQueryValue } from 'vue-router';
|
|
2
2
|
import { MaybeRefOrGetter, UnwrapNestedRefs, WatchHandle } from 'vue';
|
|
3
|
-
import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers
|
|
3
|
+
import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers';
|
|
4
4
|
export type QueryValue = LocationQueryValue | LocationQueryValue[];
|
|
5
5
|
export type DeepTransformValuesToLocationQueryValue<T> = {
|
|
6
6
|
[K in keyof T]?: T[K] extends object ? T[K] extends Array<any> ? QueryValue : DeepTransformValuesToLocationQueryValue<T[K]> : QueryValue;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","handlerConstructors: ContextStorageHandlerConstructor[]","callback: (item: ContextStorageCollectionItem) => void","key: string","options: ItemOptions","handlers","item: ContextStorageCollectionItem","removeItem: ContextStorageCollectionItem","activeItem: ContextStorageCollectionItem","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/collection.ts","../src/handlers/query/transform-helpers.ts","../src/injectionSymbols.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers.ts'\nimport { deserializeParams, serializeParams } from './helpers.ts'\nimport { contextStorageQueryHandler } from '../../symbols.ts'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types.ts'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { ContextStorageHandler, ContextStorageHandlerConstructor } from './handlers'\n\nexport type ContextStorageCollectionItem = {\n key: string\n handlers: ContextStorageHandler[]\n}\n\ninterface ItemOptions {\n key: string\n}\n\nexport class ContextStorageCollection {\n public active?: ContextStorageCollectionItem = undefined\n private collection: ContextStorageCollectionItem[] = []\n private onActiveChangeCallbacks: ((item: ContextStorageCollectionItem) => void)[] = []\n\n constructor(private handlerConstructors: ContextStorageHandlerConstructor[]) {}\n\n onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void {\n this.onActiveChangeCallbacks.push(callback)\n }\n\n first(): ContextStorageCollectionItem | undefined {\n return this.collection[0]\n }\n\n findItemByKey(key: string): ContextStorageCollectionItem | undefined {\n return this.collection.find((item) => item.key === key)\n }\n\n add(options: ItemOptions): ContextStorageCollectionItem {\n const handlers = this.handlerConstructors.map((constructor) => new constructor())\n\n const item: ContextStorageCollectionItem = { handlers, key: options.key }\n\n this.collection.push(item)\n\n return item\n }\n\n remove(removeItem: ContextStorageCollectionItem): void {\n if (this.collection.indexOf(removeItem) === -1) {\n throw new Error('[ContextStorage] Item not found in collection')\n }\n\n this.collection = this.collection.filter((item) => item !== removeItem)\n\n if (this.active === removeItem && this.collection.length > 0) {\n this.setActive(this.collection[this.collection.length - 1])\n }\n }\n\n setActive(activeItem: ContextStorageCollectionItem): void {\n if (this.active === activeItem) {\n return\n }\n\n const hasActiveBefore = this.active !== undefined\n this.active = activeItem\n\n this.collection.forEach((item) => {\n Object.values(item.handlers).forEach((handler) => {\n if (handler.setEnabled) {\n handler.setEnabled(item === activeItem, !hasActiveBefore)\n }\n })\n })\n\n this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem))\n }\n}\n","import { QueryValue } from './types.ts'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport { ContextStorageCollection } from './collection'\nexport type { ContextStorageCollectionItem } from './collection'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers.ts'\nexport type { SerializeOptions } from './handlers/query/helpers.ts'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers.ts'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","handlerConstructors: ContextStorageHandlerConstructor[]","callback: (item: ContextStorageCollectionItem) => void","key: string","options: ItemOptions","handlers","item: ContextStorageCollectionItem","removeItem: ContextStorageCollectionItem","activeItem: ContextStorageCollectionItem","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/collection.ts","../src/handlers/query/transform-helpers.ts","../src/injectionSymbols.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers'\nimport { deserializeParams, serializeParams } from './helpers'\nimport { contextStorageQueryHandler } from '../../symbols'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { ContextStorageHandler, ContextStorageHandlerConstructor } from './handlers'\n\nexport type ContextStorageCollectionItem = {\n key: string\n handlers: ContextStorageHandler[]\n}\n\ninterface ItemOptions {\n key: string\n}\n\nexport class ContextStorageCollection {\n public active?: ContextStorageCollectionItem = undefined\n private collection: ContextStorageCollectionItem[] = []\n private onActiveChangeCallbacks: ((item: ContextStorageCollectionItem) => void)[] = []\n\n constructor(private handlerConstructors: ContextStorageHandlerConstructor[]) {}\n\n onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void {\n this.onActiveChangeCallbacks.push(callback)\n }\n\n first(): ContextStorageCollectionItem | undefined {\n return this.collection[0]\n }\n\n findItemByKey(key: string): ContextStorageCollectionItem | undefined {\n return this.collection.find((item) => item.key === key)\n }\n\n add(options: ItemOptions): ContextStorageCollectionItem {\n const handlers = this.handlerConstructors.map((constructor) => new constructor())\n\n const item: ContextStorageCollectionItem = { handlers, key: options.key }\n\n this.collection.push(item)\n\n return item\n }\n\n remove(removeItem: ContextStorageCollectionItem): void {\n if (this.collection.indexOf(removeItem) === -1) {\n throw new Error('[ContextStorage] Item not found in collection')\n }\n\n this.collection = this.collection.filter((item) => item !== removeItem)\n\n if (this.active === removeItem && this.collection.length > 0) {\n this.setActive(this.collection[this.collection.length - 1])\n }\n }\n\n setActive(activeItem: ContextStorageCollectionItem): void {\n if (this.active === activeItem) {\n return\n }\n\n const hasActiveBefore = this.active !== undefined\n this.active = activeItem\n\n this.collection.forEach((item) => {\n Object.values(item.handlers).forEach((handler) => {\n if (handler.setEnabled) {\n handler.setEnabled(item === activeItem, !hasActiveBefore)\n }\n })\n })\n\n this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem))\n }\n}\n","import { QueryValue } from './types'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport { ContextStorageCollection } from './collection'\nexport type { ContextStorageCollectionItem } from './collection'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers'\nexport type { SerializeOptions } from './handlers/query/helpers'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -3,9 +3,9 @@ export { ContextStorageCollection } from './collection';
|
|
|
3
3
|
export type { ContextStorageCollectionItem } from './collection';
|
|
4
4
|
export type { ContextStorageHandler, ContextStorageHandlerConstructor, RegisterBaseOptions, } from './handlers';
|
|
5
5
|
export { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query';
|
|
6
|
-
export { deserializeParams, serializeParams } from './handlers/query/helpers
|
|
7
|
-
export type { SerializeOptions } from './handlers/query/helpers
|
|
8
|
-
export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers
|
|
6
|
+
export { deserializeParams, serializeParams } from './handlers/query/helpers';
|
|
7
|
+
export type { SerializeOptions } from './handlers/query/helpers';
|
|
8
|
+
export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers';
|
|
9
9
|
export { contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandlerInjectKey, } from './injectionSymbols';
|
|
10
10
|
export { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols';
|
|
11
11
|
export declare const defaultHandlers: ContextStorageHandlerConstructor[];
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ export { ContextStorageCollection } from './collection';
|
|
|
3
3
|
export type { ContextStorageCollectionItem } from './collection';
|
|
4
4
|
export type { ContextStorageHandler, ContextStorageHandlerConstructor, RegisterBaseOptions, } from './handlers';
|
|
5
5
|
export { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query';
|
|
6
|
-
export { deserializeParams, serializeParams } from './handlers/query/helpers
|
|
7
|
-
export type { SerializeOptions } from './handlers/query/helpers
|
|
8
|
-
export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers
|
|
6
|
+
export { deserializeParams, serializeParams } from './handlers/query/helpers';
|
|
7
|
+
export type { SerializeOptions } from './handlers/query/helpers';
|
|
8
|
+
export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers';
|
|
9
9
|
export { contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandlerInjectKey, } from './injectionSymbols';
|
|
10
10
|
export { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols';
|
|
11
11
|
export declare const defaultHandlers: ContextStorageHandlerConstructor[];
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","handlerConstructors: ContextStorageHandlerConstructor[]","callback: (item: ContextStorageCollectionItem) => void","key: string","options: ItemOptions","handlers","item: ContextStorageCollectionItem","removeItem: ContextStorageCollectionItem","activeItem: ContextStorageCollectionItem","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/collection.ts","../src/handlers/query/transform-helpers.ts","../src/injectionSymbols.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers.ts'\nimport { deserializeParams, serializeParams } from './helpers.ts'\nimport { contextStorageQueryHandler } from '../../symbols.ts'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types.ts'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { ContextStorageHandler, ContextStorageHandlerConstructor } from './handlers'\n\nexport type ContextStorageCollectionItem = {\n key: string\n handlers: ContextStorageHandler[]\n}\n\ninterface ItemOptions {\n key: string\n}\n\nexport class ContextStorageCollection {\n public active?: ContextStorageCollectionItem = undefined\n private collection: ContextStorageCollectionItem[] = []\n private onActiveChangeCallbacks: ((item: ContextStorageCollectionItem) => void)[] = []\n\n constructor(private handlerConstructors: ContextStorageHandlerConstructor[]) {}\n\n onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void {\n this.onActiveChangeCallbacks.push(callback)\n }\n\n first(): ContextStorageCollectionItem | undefined {\n return this.collection[0]\n }\n\n findItemByKey(key: string): ContextStorageCollectionItem | undefined {\n return this.collection.find((item) => item.key === key)\n }\n\n add(options: ItemOptions): ContextStorageCollectionItem {\n const handlers = this.handlerConstructors.map((constructor) => new constructor())\n\n const item: ContextStorageCollectionItem = { handlers, key: options.key }\n\n this.collection.push(item)\n\n return item\n }\n\n remove(removeItem: ContextStorageCollectionItem): void {\n if (this.collection.indexOf(removeItem) === -1) {\n throw new Error('[ContextStorage] Item not found in collection')\n }\n\n this.collection = this.collection.filter((item) => item !== removeItem)\n\n if (this.active === removeItem && this.collection.length > 0) {\n this.setActive(this.collection[this.collection.length - 1])\n }\n }\n\n setActive(activeItem: ContextStorageCollectionItem): void {\n if (this.active === activeItem) {\n return\n }\n\n const hasActiveBefore = this.active !== undefined\n this.active = activeItem\n\n this.collection.forEach((item) => {\n Object.values(item.handlers).forEach((handler) => {\n if (handler.setEnabled) {\n handler.setEnabled(item === activeItem, !hasActiveBefore)\n }\n })\n })\n\n this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem))\n }\n}\n","import { QueryValue } from './types.ts'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport { ContextStorageCollection } from './collection'\nexport type { ContextStorageCollectionItem } from './collection'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers.ts'\nexport type { SerializeOptions } from './handlers/query/helpers.ts'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers.ts'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","handlerConstructors: ContextStorageHandlerConstructor[]","callback: (item: ContextStorageCollectionItem) => void","key: string","options: ItemOptions","handlers","item: ContextStorageCollectionItem","removeItem: ContextStorageCollectionItem","activeItem: ContextStorageCollectionItem","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/collection.ts","../src/handlers/query/transform-helpers.ts","../src/injectionSymbols.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers'\nimport { deserializeParams, serializeParams } from './helpers'\nimport { contextStorageQueryHandler } from '../../symbols'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { ContextStorageHandler, ContextStorageHandlerConstructor } from './handlers'\n\nexport type ContextStorageCollectionItem = {\n key: string\n handlers: ContextStorageHandler[]\n}\n\ninterface ItemOptions {\n key: string\n}\n\nexport class ContextStorageCollection {\n public active?: ContextStorageCollectionItem = undefined\n private collection: ContextStorageCollectionItem[] = []\n private onActiveChangeCallbacks: ((item: ContextStorageCollectionItem) => void)[] = []\n\n constructor(private handlerConstructors: ContextStorageHandlerConstructor[]) {}\n\n onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void {\n this.onActiveChangeCallbacks.push(callback)\n }\n\n first(): ContextStorageCollectionItem | undefined {\n return this.collection[0]\n }\n\n findItemByKey(key: string): ContextStorageCollectionItem | undefined {\n return this.collection.find((item) => item.key === key)\n }\n\n add(options: ItemOptions): ContextStorageCollectionItem {\n const handlers = this.handlerConstructors.map((constructor) => new constructor())\n\n const item: ContextStorageCollectionItem = { handlers, key: options.key }\n\n this.collection.push(item)\n\n return item\n }\n\n remove(removeItem: ContextStorageCollectionItem): void {\n if (this.collection.indexOf(removeItem) === -1) {\n throw new Error('[ContextStorage] Item not found in collection')\n }\n\n this.collection = this.collection.filter((item) => item !== removeItem)\n\n if (this.active === removeItem && this.collection.length > 0) {\n this.setActive(this.collection[this.collection.length - 1])\n }\n }\n\n setActive(activeItem: ContextStorageCollectionItem): void {\n if (this.active === activeItem) {\n return\n }\n\n const hasActiveBefore = this.active !== undefined\n this.active = activeItem\n\n this.collection.forEach((item) => {\n Object.values(item.handlers).forEach((handler) => {\n if (handler.setEnabled) {\n handler.setEnabled(item === activeItem, !hasActiveBefore)\n }\n })\n })\n\n this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem))\n }\n}\n","import { QueryValue } from './types'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport { ContextStorageCollection } from './collection'\nexport type { ContextStorageCollectionItem } from './collection'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers'\nexport type { SerializeOptions } from './handlers/query/helpers'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,12 +4,13 @@ import { ContextStorageHandlerConstructor } from '../handlers'
|
|
|
4
4
|
import { contextStorageCollectionInjectKey } from '../injectionSymbols'
|
|
5
5
|
import { computed, defineComponent, PropType, provide } from 'vue'
|
|
6
6
|
import { useRouter } from 'vue-router'
|
|
7
|
+
import { defaultHandlers } from '../index'
|
|
7
8
|
|
|
8
9
|
export default defineComponent({
|
|
9
10
|
props: {
|
|
10
11
|
handlers: {
|
|
11
12
|
type: Object as PropType<ContextStorageHandlerConstructor[]>,
|
|
12
|
-
|
|
13
|
+
default: defaultHandlers,
|
|
13
14
|
},
|
|
14
15
|
},
|
|
15
16
|
setup({ handlers }, { slots }) {
|
package/src/components.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
export { default as ContextStorageActivator } from './components/ContextStorageActivator.vue'
|
|
3
3
|
export { default as ContextStorageCollection } from './components/ContextStorageCollection.vue'
|
|
4
4
|
export { default as ContextStorageProvider } from './components/ContextStorageProvider.vue'
|
|
5
|
-
export { default as
|
|
5
|
+
export { default as ContextStorage } from './components/ContextStorage.vue'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ContextStorageHandlerConstructor } from '../../handlers
|
|
2
|
-
import { deserializeParams, serializeParams } from './helpers
|
|
3
|
-
import { contextStorageQueryHandler } from '../../symbols
|
|
1
|
+
import { ContextStorageHandlerConstructor } from '../../handlers'
|
|
2
|
+
import { deserializeParams, serializeParams } from './helpers'
|
|
3
|
+
import { contextStorageQueryHandler } from '../../symbols'
|
|
4
4
|
import { cloneDeep, isEqual, merge, pick } from 'lodash'
|
|
5
5
|
import { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'
|
|
6
6
|
import { LocationQuery, useRoute, useRouter } from 'vue-router'
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
QueryHandlerBaseOptions,
|
|
11
11
|
RegisterQueryHandlerBaseOptions,
|
|
12
12
|
RegisterQueryHandlerOptions,
|
|
13
|
-
} from './types
|
|
13
|
+
} from './types'
|
|
14
14
|
|
|
15
15
|
export function useContextStorageQueryHandler<T extends Record<string, unknown>>(
|
|
16
16
|
data: MaybeRefOrGetter<T>,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LocationQueryValue } from 'vue-router'
|
|
2
2
|
import { MaybeRefOrGetter, UnwrapNestedRefs, WatchHandle } from 'vue'
|
|
3
|
-
import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers
|
|
3
|
+
import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers'
|
|
4
4
|
|
|
5
5
|
export type QueryValue = LocationQueryValue | LocationQueryValue[]
|
|
6
6
|
|
package/src/index.ts
CHANGED
|
@@ -14,8 +14,8 @@ export type {
|
|
|
14
14
|
export { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'
|
|
15
15
|
|
|
16
16
|
// Query helpers
|
|
17
|
-
export { deserializeParams, serializeParams } from './handlers/query/helpers
|
|
18
|
-
export type { SerializeOptions } from './handlers/query/helpers
|
|
17
|
+
export { deserializeParams, serializeParams } from './handlers/query/helpers'
|
|
18
|
+
export type { SerializeOptions } from './handlers/query/helpers'
|
|
19
19
|
|
|
20
20
|
// Query transform helpers
|
|
21
21
|
export {
|
|
@@ -25,7 +25,7 @@ export {
|
|
|
25
25
|
asNumberArray,
|
|
26
26
|
asString,
|
|
27
27
|
transform,
|
|
28
|
-
} from './handlers/query/transform-helpers
|
|
28
|
+
} from './handlers/query/transform-helpers'
|
|
29
29
|
|
|
30
30
|
// Injection symbols
|
|
31
31
|
export {
|
package/src/plugin.ts
CHANGED
|
@@ -2,14 +2,14 @@ import type { App, Plugin } from 'vue'
|
|
|
2
2
|
import ContextStorageActivator from './components/ContextStorageActivator.vue'
|
|
3
3
|
import ContextStorageCollection from './components/ContextStorageCollection.vue'
|
|
4
4
|
import ContextStorageProvider from './components/ContextStorageProvider.vue'
|
|
5
|
-
import
|
|
5
|
+
import ContextStorage from './components/ContextStorage.vue'
|
|
6
6
|
|
|
7
7
|
export const VueContextStoragePlugin: Plugin = {
|
|
8
8
|
install(app: App) {
|
|
9
9
|
app.component('ContextStorageActivator', ContextStorageActivator)
|
|
10
10
|
app.component('ContextStorageCollection', ContextStorageCollection)
|
|
11
11
|
app.component('ContextStorageProvider', ContextStorageProvider)
|
|
12
|
-
app.component('
|
|
12
|
+
app.component('ContextStorage', ContextStorage)
|
|
13
13
|
},
|
|
14
14
|
}
|
|
15
15
|
|
|
File without changes
|