@hybridly/core 0.10.0-beta.16 → 0.10.0-beta.18

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/dist/index.d.mts CHANGED
@@ -271,11 +271,23 @@ interface CloseDialogOptions extends HybridRequestOptions {
271
271
  local?: boolean;
272
272
  }
273
273
  //#endregion
274
+ //#region src/query.d.ts
275
+ type QueryArrayFormat = 'indices' | 'brackets';
276
+ type QueryValue = string | number | boolean | null | undefined | QueryValue[] | Set<QueryValue> | {
277
+ [key: string]: QueryValue;
278
+ };
279
+ interface StringifyQueryOptions {
280
+ arrayFormat?: QueryArrayFormat;
281
+ addQueryPrefix?: boolean;
282
+ }
283
+ declare function parseQueryString(query: string): Record<string, any>;
284
+ declare function stringifyQueryString(value: QueryValue, options?: StringifyQueryOptions): string;
285
+ //#endregion
274
286
  //#region src/url.d.ts
275
287
  type UrlResolvable = string | URL | Location;
276
288
  type UrlTransformable = BaseUrlTransformable | ((string: URL) => BaseUrlTransformable);
277
289
  type BaseUrlTransformable = Partial<Omit<URL, 'searchParams' | 'toJSON' | 'toString'>> & {
278
- query?: any;
290
+ query?: Record<string, QueryValue>;
279
291
  trailingSlash?: boolean;
280
292
  };
281
293
  /** Normalizes the given input to an URL. */
@@ -575,15 +587,6 @@ declare const router: {
575
587
  /** Creates the hybridly router. */
576
588
  declare function createRouter(options: RouterContextOptions): Promise<InternalRouterContext>;
577
589
  //#endregion
578
- //#region src/query.d.ts
579
- type QueryArrayFormat = 'indices' | 'brackets';
580
- interface StringifyQueryOptions {
581
- arrayFormat?: QueryArrayFormat;
582
- addQueryPrefix?: boolean;
583
- }
584
- declare function parseQueryString(query: string): Record<string, any>;
585
- declare function stringifyQueryString(value: unknown, options?: StringifyQueryOptions): string;
586
- //#endregion
587
590
  //#region src/authorization.d.ts
588
591
  interface Authorizable<Authorizations extends Record<string, boolean>> {
589
592
  authorization: Authorizations;
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { t as __exportAll } from "./_chunks/chunk.mjs";
2
2
  import { debug, hasFiles, merge, mergeObject, objectToFormData, random, showResponseErrorModal, wrap } from "@hybridly/utils";
3
3
  import { trimEnd } from "es-toolkit/string";
4
- import { parse, stringify } from "picoquery";
4
+ import { isPlainObject } from "es-toolkit/predicate";
5
+ import { parse, stringify } from "neoqs";
5
6
  import { debounce } from "es-toolkit/function";
6
7
  import { parse as parse$1, stringify as stringify$1 } from "superjson";
7
8
  import { get, set, uniqBy } from "es-toolkit/compat";
@@ -9,35 +10,15 @@ import { get, set, uniqBy } from "es-toolkit/compat";
9
10
  function parseQueryString(query) {
10
11
  const source = query.startsWith("?") ? query.slice(1) : query;
11
12
  if (!source) return {};
12
- return parse(source, {
13
- nesting: true,
14
- nestingSyntax: "index",
15
- arrayRepeat: true,
16
- arrayRepeatSyntax: "bracket"
17
- });
13
+ return parse(source);
18
14
  }
19
15
  function stringifyQueryString(value, options = {}) {
20
- const normalizedQuery = unescapeBracketSyntaxInKeys(stringify(normalizeQueryValue(value), {
21
- nesting: true,
22
- nestingSyntax: "index",
23
- arrayRepeat: (options.arrayFormat ?? "brackets") === "brackets",
24
- arrayRepeatSyntax: "bracket"
25
- }));
26
- if (!normalizedQuery) return "";
27
- return options.addQueryPrefix ? `?${normalizedQuery}` : normalizedQuery;
28
- }
29
- function unescapeBracketSyntaxInKeys(query) {
30
- if (!query) return query;
31
- return query.split("&").map((entry) => {
32
- const separator = entry.indexOf("=");
33
- if (separator < 0) return decodeBracketSyntax(entry);
34
- const key = entry.slice(0, separator);
35
- const value = entry.slice(separator);
36
- return `${decodeBracketSyntax(key)}${value}`;
37
- }).join("&");
38
- }
39
- function decodeBracketSyntax(value) {
40
- return value.replace(/%5B/gi, "[").replace(/%5D/gi, "]");
16
+ const query = stringify(normalizeQueryValue(value), {
17
+ arrayFormat: options.arrayFormat ?? "brackets",
18
+ encodeValuesOnly: true
19
+ });
20
+ if (!query) return "";
21
+ return options.addQueryPrefix ? `?${query}` : query;
41
22
  }
42
23
  function normalizeQueryValue(value) {
43
24
  if (value instanceof Set) return [...value].map((entry) => normalizeQueryValue(entry));
@@ -48,11 +29,6 @@ function normalizeQueryValue(value) {
48
29
  }), {});
49
30
  return value;
50
31
  }
51
- function isPlainObject(value) {
52
- if (typeof value !== "object" || value === null) return false;
53
- const prototype = Object.getPrototypeOf(value);
54
- return prototype === null || prototype === Object.prototype;
55
- }
56
32
  //#endregion
57
33
  //#region src/url.ts
58
34
  /** Normalizes the given input to an URL. */
@@ -69,9 +45,8 @@ function makeUrl(href, transformations = {}) {
69
45
  transformations = typeof transformations === "function" ? transformations(url) ?? {} : transformations ?? {};
70
46
  Object.entries(transformations).forEach(([key, value]) => {
71
47
  if (key === "query") {
72
- const currentQueryParameters = merge(parseQueryString(url.search), value, { mergePlainObjects: true });
73
48
  key = "search";
74
- value = stringifyQueryString(currentQueryParameters, { arrayFormat: "brackets" });
49
+ value = stringifyQueryString(merge(parseQueryString(url.search), value, { mergePlainObjects: true }), { arrayFormat: "brackets" });
75
50
  }
76
51
  Reflect.set(url, key, value);
77
52
  });
@@ -610,6 +585,9 @@ function createPromiseWithResolvers() {
610
585
  reject
611
586
  };
612
587
  }
588
+ function evaluateConditionalOption(options, option) {
589
+ return typeof option === "function" ? option(options) : option;
590
+ }
613
591
  //#endregion
614
592
  //#region src/router/request/request.ts
615
593
  function createPendingHybridRequest(options) {
@@ -699,8 +677,8 @@ async function transformOptions(options) {
699
677
  debug.router("Converted data to FormData.", options.data);
700
678
  }
701
679
  if (!(options.data instanceof FormData) && options.method === "GET" && Object.keys(options.data ?? {}).length) {
702
- debug.router("Transforming data to query parameters.", options.data);
703
680
  options.url = makeUrl(options.url ?? context.url, { query: options.data });
681
+ debug.router("Transforming data to query parameters.", options.data, options.url);
704
682
  options.data = {};
705
683
  }
706
684
  if ([
@@ -734,13 +712,10 @@ async function navigate(options) {
734
712
  options.payload ??= payloadFromContext();
735
713
  options.payload.view ??= payloadFromContext().view;
736
714
  options.payload.view.properties = options.properties ?? options.payload.view.properties;
737
- function evaluateConditionalOption(option) {
738
- return typeof option === "function" ? option(options) : option;
739
- }
740
- const shouldPreserveState = evaluateConditionalOption(options.preserveState);
741
- const shouldPreserveScroll = evaluateConditionalOption(options.preserveScroll);
742
- const shouldReplaceHistory = evaluateConditionalOption(options.replace);
743
- const shouldReplaceUrl = evaluateConditionalOption(options.preserveUrl);
715
+ const shouldPreserveState = evaluateConditionalOption(options, options.preserveState);
716
+ const shouldPreserveScroll = evaluateConditionalOption(options, options.preserveScroll);
717
+ const shouldReplaceHistory = evaluateConditionalOption(options, options.replace);
718
+ const shouldReplaceUrl = evaluateConditionalOption(options, options.preserveUrl);
744
719
  const shouldPreserveView = !options.payload.view.component;
745
720
  if (shouldPreserveState && getHistoryMemo() && options.payload.view.component === context.view.component) {
746
721
  debug.history("Setting the memo from this history entry into the current context.");
@@ -913,7 +888,7 @@ async function handleHybridRequestResponse({ request, response }) {
913
888
  if (options.mode !== "async" || context.view.component === request.view.component) {
914
889
  const properties = (() => {
915
890
  if (!payload.view && !isPartial(options)) return;
916
- if (!payload.view.component || payload.view.component === context.view.component) return resolveProperties(context.view.properties, payload.view);
891
+ if (!payload.view.component || payload.view.component === context.view.component) return resolveProperties(context.view.properties, payload.view, { mergeWithOriginal: evaluateConditionalOption(options, options.preserveState) !== false });
917
892
  })();
918
893
  if (properties) debug.router("Merged properties:", properties);
919
894
  await navigate({
@@ -944,13 +919,15 @@ function isHybridResponse(response) {
944
919
  return response.headers.has(HYBRIDLY_HEADER);
945
920
  }
946
921
  function isPartial(options) {
947
- return options.only !== void 0 || options.except !== void 0;
922
+ return options.only !== void 0 || options.except !== void 0 || options.reset !== void 0;
948
923
  }
949
- function resolveProperties(original, payload) {
950
- const mergedPayloadProperties = merge(original, payload.properties);
951
- (payload.mergeable ?? []).forEach(([mergeableProperty, prepends, uniqueBy]) => {
924
+ function resolveProperties(original, payload, options) {
925
+ const mergeable = payload.mergeable ?? [];
926
+ const mergedPayloadProperties = options.mergeWithOriginal ? merge(original, payload.properties) : payload.properties;
927
+ mergeable.forEach(([mergeableProperty, prepends, uniqueBy]) => {
952
928
  const originalValue = get(original, mergeableProperty);
953
929
  const newValue = get(payload.properties, mergeableProperty);
930
+ if (!options.mergeWithOriginal && newValue === void 0) return;
954
931
  const mergeArrays = (current, incoming) => {
955
932
  const merged = prepends === true ? [...incoming, ...current] : [...current, ...incoming];
956
933
  if (typeof uniqueBy !== "string") return merged;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hybridly/core",
3
3
  "type": "module",
4
- "version": "0.10.0-beta.16",
4
+ "version": "0.10.0-beta.18",
5
5
  "description": "Core functionality of Hybridly",
6
6
  "author": "Enzo Innocenzi <enzo@innocenzi.dev>",
7
7
  "license": "MIT",
@@ -40,8 +40,8 @@
40
40
  "build:stub": "obuild --stub"
41
41
  },
42
42
  "dependencies": {
43
- "@hybridly/utils": "0.10.0-beta.16",
44
- "picoquery": "^2.5.0",
43
+ "@hybridly/utils": "0.10.0-beta.18",
44
+ "neoqs": "^6.13.0",
45
45
  "superjson": "^2.2.2",
46
46
  "es-toolkit": "^1.45.1"
47
47
  },