@jskit-ai/users-web 0.1.172 → 0.1.174

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/package.json +18 -149
  2. package/src/client/composables/account-settings/accountSettingsAvatarUploadRuntime.js +2 -2
  3. package/src/client/composables/useAccountSettingsRuntime.js +3 -3
  4. package/src/client/index.js +0 -11
  5. package/test/exportsContract.test.js +3 -29
  6. package/test/settingsPlacementContract.test.js +10 -0
  7. package/fixtures/crud-list-date-filters/App.vue +0 -107
  8. package/fixtures/crud-list-date-filters/index.html +0 -12
  9. package/fixtures/crud-list-date-filters/main.js +0 -24
  10. package/fixtures/crud-list-date-filters/vite.config.mjs +0 -18
  11. package/src/client/bulkActions.js +0 -47
  12. package/src/client/components/CrudAddEditScreen.vue +0 -186
  13. package/src/client/components/CrudDeleteAction.vue +0 -93
  14. package/src/client/components/CrudListBulkActionSurface.vue +0 -126
  15. package/src/client/components/CrudListDateFilterControl.vue +0 -188
  16. package/src/client/components/CrudListFilterSurface.vue +0 -388
  17. package/src/client/components/CrudListRecordActionMenu.vue +0 -120
  18. package/src/client/components/CrudListScreen.vue +0 -501
  19. package/src/client/components/CrudViewScreen.vue +0 -197
  20. package/src/client/composables/crud/crudBindingSupport.js +0 -75
  21. package/src/client/composables/crud/crudHttpClientSupport.js +0 -57
  22. package/src/client/composables/crud/crudJsonApiTransportSupport.js +0 -145
  23. package/src/client/composables/crud/crudLookupFieldLabelSupport.js +0 -151
  24. package/src/client/composables/crud/crudLookupFieldRuntime.js +0 -251
  25. package/src/client/composables/crud/crudSchemaFormHelpers.js +0 -464
  26. package/src/client/composables/internal/crudListFilterLookupSupport.js +0 -161
  27. package/src/client/composables/internal/crudListParentTitleSupport.js +0 -171
  28. package/src/client/composables/internal/useOperationScope.js +0 -144
  29. package/src/client/composables/records/useAddEdit.js +0 -224
  30. package/src/client/composables/records/useCrudAddEdit.js +0 -227
  31. package/src/client/composables/records/useCrudList.js +0 -101
  32. package/src/client/composables/records/useCrudView.js +0 -47
  33. package/src/client/composables/records/useList.js +0 -500
  34. package/src/client/composables/records/useView.js +0 -164
  35. package/src/client/composables/runtime/addEditUiRuntime.js +0 -130
  36. package/src/client/composables/runtime/listUiRuntime.js +0 -123
  37. package/src/client/composables/runtime/modelStateHelpers.js +0 -90
  38. package/src/client/composables/runtime/operationAdapters.js +0 -34
  39. package/src/client/composables/runtime/operationUiHelpers.js +0 -125
  40. package/src/client/composables/runtime/operationValidationHelpers.js +0 -51
  41. package/src/client/composables/runtime/useAddEditCore.js +0 -112
  42. package/src/client/composables/runtime/useCommandCore.js +0 -123
  43. package/src/client/composables/runtime/useEndpointResource.js +0 -199
  44. package/src/client/composables/runtime/useFieldErrorBag.js +0 -61
  45. package/src/client/composables/runtime/useListCore.js +0 -112
  46. package/src/client/composables/runtime/useUiFeedback.js +0 -98
  47. package/src/client/composables/runtime/useViewCore.js +0 -93
  48. package/src/client/composables/runtime/viewUiRuntime.js +0 -96
  49. package/src/client/composables/support/errorMessageHelpers.js +0 -66
  50. package/src/client/composables/support/listQueryParamSupport.js +0 -473
  51. package/src/client/composables/support/listSearchSupport.js +0 -70
  52. package/src/client/composables/support/refValueHelpers.js +0 -19
  53. package/src/client/composables/support/requestQueryRuntimeSupport.js +0 -141
  54. package/src/client/composables/support/resourceLoadStateHelpers.js +0 -208
  55. package/src/client/composables/support/routeTemplateHelpers.js +0 -285
  56. package/src/client/composables/support/scopeHelpers.js +0 -145
  57. package/src/client/composables/useAccess.js +0 -109
  58. package/src/client/composables/useCommand.js +0 -118
  59. package/src/client/composables/useCrudAddEditScreen.js +0 -88
  60. package/src/client/composables/useCrudDeleteAction.js +0 -160
  61. package/src/client/composables/useCrudListBulkActions.js +0 -147
  62. package/src/client/composables/useCrudListFilterLookups.js +0 -146
  63. package/src/client/composables/useCrudListFilters.js +0 -339
  64. package/src/client/composables/useCrudListParentTitle.js +0 -151
  65. package/src/client/composables/useCrudListRowActions.js +0 -144
  66. package/src/client/composables/useCrudListScreen.js +0 -237
  67. package/src/client/composables/useCrudViewScreen.js +0 -77
  68. package/src/client/composables/usePagedCollection.js +0 -181
  69. package/src/client/composables/useRealtimeQueryInvalidation.js +0 -156
  70. package/src/client/composables/useScopeRuntime.js +0 -135
  71. package/src/client/filters.js +0 -15
  72. package/src/client/lib/httpClient.js +0 -47
  73. package/src/client/lib/permissions.js +0 -34
  74. package/src/client/rowActions.js +0 -47
  75. package/src/client/support/contractGuards.js +0 -34
  76. package/src/client/support/crudListDateFilterSupport.js +0 -91
  77. package/test/addEditUiRuntime.test.js +0 -110
  78. package/test/crudBindingSupport.test.js +0 -110
  79. package/test/crudHttpClientSupport.test.js +0 -77
  80. package/test/crudJsonApiTransportSupport.test.js +0 -179
  81. package/test/crudListBulkActionSurface.test.js +0 -27
  82. package/test/crudListDateFilterSupport.test.js +0 -92
  83. package/test/crudListDateFilterSurface.browser.test.js +0 -182
  84. package/test/crudListFilterSurface.test.js +0 -90
  85. package/test/crudLookupFieldRuntime.test.js +0 -264
  86. package/test/crudScreenComponents.test.js +0 -117
  87. package/test/errorIntentContract.test.js +0 -31
  88. package/test/errorMessageHelpers.test.js +0 -28
  89. package/test/listQueryParamSupport.test.js +0 -223
  90. package/test/listUiRuntime.test.js +0 -102
  91. package/test/operationValidationHelpers.test.js +0 -64
  92. package/test/permissions.test.js +0 -35
  93. package/test/refValueHelpers.test.js +0 -14
  94. package/test/requestTransportOptions.test.js +0 -457
  95. package/test/resourceLoadStateHelpers.test.js +0 -189
  96. package/test/routeTemplateHelpers.test.js +0 -85
  97. package/test/scopeHelpers.test.js +0 -57
  98. package/test/useAddEditCore.test.js +0 -124
  99. package/test/useAddEditRequestQueryParams.test.js +0 -190
  100. package/test/useCrudAddEdit.test.js +0 -415
  101. package/test/useCrudDeleteAction.test.js +0 -139
  102. package/test/useCrudListBulkActions.test.js +0 -65
  103. package/test/useCrudListFilterLookups.test.js +0 -114
  104. package/test/useCrudListFilters.test.js +0 -293
  105. package/test/useCrudListParentTitle.test.js +0 -262
  106. package/test/useCrudListRowActions.test.js +0 -77
  107. package/test/useListRouteInitialization.test.js +0 -337
  108. package/test/useListSearchSupport.test.js +0 -61
  109. package/test/usePagedCollection.test.js +0 -53
  110. package/test/useViewRequestQueryParams.test.js +0 -20
  111. package/test/viewCoreLoading.test.js +0 -44
  112. package/test/viewUiRuntime.test.js +0 -95
@@ -1,19 +0,0 @@
1
- import { unref } from "vue";
2
-
3
- function resolveEnabledRef(value) {
4
- if (value === undefined) {
5
- return true;
6
- }
7
-
8
- if (typeof value === "function") {
9
- return Boolean(value());
10
- }
11
-
12
- return Boolean(unref(value));
13
- }
14
-
15
- function resolveTextRef(value) {
16
- return String(unref(value) || "").trim();
17
- }
18
-
19
- export { resolveEnabledRef, resolveTextRef };
@@ -1,141 +0,0 @@
1
- import { computed, unref } from "vue";
2
- import {
3
- buildJsonApiFieldsetsToken,
4
- normalizeJsonApiFieldsets
5
- } from "@jskit-ai/kernel/shared/support/jsonApiFieldsets";
6
- import {
7
- resolveQueryParamDescriptors,
8
- resolveActiveQueryParamEntries,
9
- buildQueryParamEntriesToken
10
- } from "./listQueryParamSupport.js";
11
-
12
- function resolveRequestQueryContext(context = null) {
13
- const source = unref(context);
14
- return source && typeof source === "object" && !Array.isArray(source) ? source : {};
15
- }
16
-
17
- function resolveRequestQueryBaseKey(sourceQueryKey = null) {
18
- const source = unref(sourceQueryKey);
19
- if (Array.isArray(source)) {
20
- return [...source];
21
- }
22
- if (source == null) {
23
- return [];
24
- }
25
- return [source];
26
- }
27
-
28
- function resolveRequestFieldsets(requestFieldsets = null, context = {}) {
29
- const source = typeof requestFieldsets === "function"
30
- ? requestFieldsets(context)
31
- : unref(requestFieldsets);
32
- return normalizeJsonApiFieldsets(source);
33
- }
34
-
35
- function appendRequestQueryValue(target = {}, key = "", values = []) {
36
- const normalizedKey = String(key || "").trim();
37
- const normalizedValues = (Array.isArray(values) ? values : [])
38
- .map((value) => String(value ?? "").trim())
39
- .filter(Boolean);
40
- if (!normalizedKey || normalizedValues.length < 1) {
41
- return;
42
- }
43
-
44
- const currentValue = target[normalizedKey];
45
- if (currentValue === undefined) {
46
- target[normalizedKey] = normalizedValues.length === 1 ? normalizedValues[0] : [...normalizedValues];
47
- return;
48
- }
49
-
50
- const currentValues = Array.isArray(currentValue) ? [...currentValue] : [currentValue];
51
- target[normalizedKey] = [...currentValues, ...normalizedValues];
52
- }
53
-
54
- function buildRequestQueryObject(entries = [], { fieldsets = null } = {}) {
55
- const sourceEntries = Array.isArray(entries) ? entries : [];
56
- const query = {};
57
-
58
- for (const entry of sourceEntries) {
59
- appendRequestQueryValue(query, entry?.key, entry?.values);
60
- }
61
-
62
- const normalizedFieldsets = normalizeJsonApiFieldsets(fieldsets);
63
- return Object.freeze({
64
- ...query,
65
- ...(Object.keys(normalizedFieldsets).length > 0
66
- ? { fields: normalizedFieldsets }
67
- : {})
68
- });
69
- }
70
-
71
- function createRequestQueryRuntime({
72
- requestQueryParams = null,
73
- requestFieldsets = null,
74
- context = null,
75
- sourceQueryKey = null
76
- } = {}) {
77
- const requestQueryParamDescriptors = computed(() => {
78
- return resolveQueryParamDescriptors(requestQueryParams, resolveRequestQueryContext(context));
79
- });
80
- const activeRequestQueryParamEntries = computed(() => {
81
- return resolveActiveQueryParamEntries(requestQueryParamDescriptors.value);
82
- });
83
- const activeRequestQueryParamsToken = computed(() => {
84
- return buildQueryParamEntriesToken(activeRequestQueryParamEntries.value);
85
- });
86
- const activeRequestFieldsets = computed(() => {
87
- return resolveRequestFieldsets(
88
- requestFieldsets,
89
- resolveRequestQueryContext(context)
90
- );
91
- });
92
- const activeRequestFieldsetsToken = computed(() => {
93
- return buildJsonApiFieldsetsToken(activeRequestFieldsets.value);
94
- });
95
- const queryKeyParts = computed(() => {
96
- const parts = [];
97
- if (activeRequestQueryParamsToken.value) {
98
- parts.push("__request_query__", activeRequestQueryParamsToken.value);
99
- }
100
- if (activeRequestFieldsetsToken.value) {
101
- parts.push("__request_fieldsets__", activeRequestFieldsetsToken.value);
102
- }
103
- return Object.freeze(parts);
104
- });
105
- const queryKey = computed(() => {
106
- if (queryKeyParts.value.length < 1) {
107
- return unref(sourceQueryKey);
108
- }
109
-
110
- return [
111
- ...resolveRequestQueryBaseKey(sourceQueryKey),
112
- ...queryKeyParts.value
113
- ];
114
- });
115
- const requestQuery = computed(() => {
116
- const query = buildRequestQueryObject(activeRequestQueryParamEntries.value, {
117
- fieldsets: activeRequestFieldsets.value
118
- });
119
- if (Object.keys(query).length < 1) {
120
- return null;
121
- }
122
-
123
- return query;
124
- });
125
-
126
- return Object.freeze({
127
- requestQueryParamDescriptors,
128
- activeRequestQueryParamEntries,
129
- activeRequestQueryParamsToken,
130
- activeRequestFieldsets,
131
- activeRequestFieldsetsToken,
132
- queryKeyParts,
133
- queryKey,
134
- requestQuery
135
- });
136
- }
137
-
138
- export {
139
- buildRequestQueryObject,
140
- createRequestQueryRuntime
141
- };
@@ -1,208 +0,0 @@
1
- import { unref } from "vue";
2
-
3
- function hasResolvedQueryData({ query = null, data = null } = {}) {
4
- const querySucceeded = Boolean(unref(query?.isSuccess));
5
- const hasDataPayload = unref(data) != null;
6
-
7
- return querySucceeded || hasDataPayload;
8
- }
9
-
10
- function mergeQueryMeta(queryOptions = null, meta = {}) {
11
- const sourceOptions =
12
- queryOptions && typeof queryOptions === "object" && !Array.isArray(queryOptions) ? queryOptions : {};
13
- const sourceMeta =
14
- sourceOptions.meta && typeof sourceOptions.meta === "object" && !Array.isArray(sourceOptions.meta)
15
- ? sourceOptions.meta
16
- : {};
17
- const sourceJskitMeta =
18
- sourceMeta.jskit && typeof sourceMeta.jskit === "object" && !Array.isArray(sourceMeta.jskit)
19
- ? sourceMeta.jskit
20
- : {};
21
- const nextJskitMeta =
22
- meta.jskit && typeof meta.jskit === "object" && !Array.isArray(meta.jskit)
23
- ? meta.jskit
24
- : {};
25
-
26
- return {
27
- ...sourceOptions,
28
- meta: {
29
- ...sourceMeta,
30
- ...meta,
31
- jskit: {
32
- ...sourceJskitMeta,
33
- ...nextJskitMeta
34
- }
35
- }
36
- };
37
- }
38
-
39
- function normalizeText(value = "") {
40
- return String(value || "").trim();
41
- }
42
-
43
- function firstNormalizedText(...values) {
44
- for (const value of values) {
45
- const normalized = normalizeText(value);
46
- if (normalized) {
47
- return normalized;
48
- }
49
- }
50
- return "";
51
- }
52
-
53
- function firstNonNegativeFiniteNumber(...values) {
54
- for (const value of values) {
55
- const numberValue = Number(value);
56
- if (Number.isFinite(numberValue)) {
57
- return Math.max(0, numberValue);
58
- }
59
- }
60
- return null;
61
- }
62
-
63
- function normalizePlainObject(value = null) {
64
- return value && typeof value === "object" && !Array.isArray(value) ? value : {};
65
- }
66
-
67
- function normalizeRequestRecoveryInput(requestRecovery = null) {
68
- if (typeof requestRecovery === "string") {
69
- return {
70
- label: requestRecovery
71
- };
72
- }
73
- return normalizePlainObject(requestRecovery);
74
- }
75
-
76
- function normalizeRequestRecoveryMethod(value = "") {
77
- return normalizeText(value).toUpperCase();
78
- }
79
-
80
- function isRequestRecoveryMetaDisabled(sourceJskitMeta = {}) {
81
- return sourceJskitMeta.requestRecovery === false;
82
- }
83
-
84
- function hasUsableMetaValue(source = {}, key = "") {
85
- return Object.hasOwn(source, key) && source[key] !== undefined && source[key] !== null && source[key] !== "";
86
- }
87
-
88
- function buildRequestRecoveryMeta(requestRecovery = null, defaults = {}) {
89
- if (requestRecovery === false) {
90
- return {
91
- jskit: {
92
- requestRecovery: false
93
- }
94
- };
95
- }
96
-
97
- const fallback = normalizePlainObject(defaults);
98
- const source = normalizeRequestRecoveryInput(requestRecovery);
99
- if (source.requestRecovery === false || source.enabled === false) {
100
- return {
101
- jskit: {
102
- requestRecovery: false
103
- }
104
- };
105
- }
106
-
107
- const label = firstNormalizedText(
108
- source.requestRecoveryLabel,
109
- source.label,
110
- fallback.requestRecoveryLabel,
111
- fallback.label
112
- );
113
- const recoverySource = firstNormalizedText(
114
- source.requestRecoverySource,
115
- source.source,
116
- fallback.requestRecoverySource,
117
- fallback.source
118
- );
119
- const dedupeKey = firstNormalizedText(
120
- source.requestRecoveryDedupeKey,
121
- source.dedupeKey,
122
- fallback.requestRecoveryDedupeKey,
123
- fallback.dedupeKey
124
- );
125
- const method = normalizeRequestRecoveryMethod(
126
- firstNormalizedText(
127
- source.requestRecoveryMethod,
128
- source.method,
129
- fallback.requestRecoveryMethod,
130
- fallback.method
131
- )
132
- );
133
- const dedupeWindowMs = firstNonNegativeFiniteNumber(
134
- source.requestRecoveryDedupeWindowMs,
135
- source.dedupeWindowMs,
136
- fallback.requestRecoveryDedupeWindowMs,
137
- fallback.dedupeWindowMs
138
- );
139
-
140
- const jskit = {};
141
- if (label) {
142
- jskit.requestRecoveryLabel = label;
143
- }
144
- if (recoverySource) {
145
- jskit.requestRecoverySource = recoverySource;
146
- }
147
- if (dedupeKey) {
148
- jskit.requestRecoveryDedupeKey = dedupeKey;
149
- }
150
- if (method) {
151
- jskit.requestRecoveryMethod = method;
152
- }
153
- if (dedupeWindowMs !== null) {
154
- jskit.requestRecoveryDedupeWindowMs = dedupeWindowMs;
155
- }
156
-
157
- return Object.keys(jskit).length > 0 ? { jskit } : {};
158
- }
159
-
160
- function resolveRequestRecoveryDefaults(queryOptions = null, defaults = {}) {
161
- const sourceOptions = normalizePlainObject(queryOptions);
162
- const sourceMeta = normalizePlainObject(sourceOptions.meta);
163
- const sourceJskitMeta = normalizePlainObject(sourceMeta.jskit);
164
- const fallback = normalizePlainObject(defaults);
165
- if (isRequestRecoveryMetaDisabled(sourceJskitMeta)) {
166
- return {};
167
- }
168
-
169
- const hasExplicitLabel = hasUsableMetaValue(sourceJskitMeta, "requestRecoveryLabel");
170
- const hasExplicitSource = hasUsableMetaValue(sourceJskitMeta, "requestRecoverySource");
171
- const hasExplicitDedupeKey = hasUsableMetaValue(sourceJskitMeta, "requestRecoveryDedupeKey");
172
- const hasExplicitDedupeWindowMs = hasUsableMetaValue(sourceJskitMeta, "requestRecoveryDedupeWindowMs");
173
- const hasExplicitMethod = hasUsableMetaValue(sourceJskitMeta, "requestRecoveryMethod");
174
-
175
- return {
176
- ...fallback,
177
- requestRecoveryLabel: hasExplicitLabel ? "" : fallback.requestRecoveryLabel,
178
- label: hasExplicitLabel ? "" : fallback.label,
179
- requestRecoverySource: hasExplicitSource ? "" : fallback.requestRecoverySource,
180
- source: hasExplicitSource ? "" : fallback.source,
181
- requestRecoveryDedupeKey: hasExplicitDedupeKey ? "" : fallback.requestRecoveryDedupeKey,
182
- dedupeKey: hasExplicitDedupeKey ? "" : fallback.dedupeKey,
183
- requestRecoveryDedupeWindowMs: hasExplicitDedupeWindowMs ? "" : fallback.requestRecoveryDedupeWindowMs,
184
- dedupeWindowMs: hasExplicitDedupeWindowMs ? "" : fallback.dedupeWindowMs,
185
- requestRecoveryMethod: hasExplicitMethod ? "" : fallback.requestRecoveryMethod,
186
- method: hasExplicitMethod ? "" : fallback.method
187
- };
188
- }
189
-
190
- function mergeRequestRecoveryQueryMeta(queryOptions = null, requestRecovery = null, defaults = {}) {
191
- const sourceOptions = normalizePlainObject(queryOptions);
192
- const effectiveDefaults =
193
- requestRecovery == null
194
- ? resolveRequestRecoveryDefaults(sourceOptions, defaults)
195
- : normalizePlainObject(defaults);
196
- const meta = buildRequestRecoveryMeta(requestRecovery, effectiveDefaults);
197
- if (Object.keys(meta).length < 1) {
198
- return sourceOptions;
199
- }
200
- return mergeQueryMeta(sourceOptions, meta);
201
- }
202
-
203
- export {
204
- buildRequestRecoveryMeta,
205
- hasResolvedQueryData,
206
- mergeQueryMeta,
207
- mergeRequestRecoveryQueryMeta
208
- };
@@ -1,285 +0,0 @@
1
- import { unref } from "vue";
2
- import { asPlainObject } from "./scopeHelpers.js";
3
-
4
- const ROUTE_PARAM_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]*$/;
5
-
6
- function normalizeRouteParamName(value = "", { context = "users-web route param" } = {}) {
7
- const normalizedValue = String(value || "").trim();
8
- if (!normalizedValue) {
9
- throw new TypeError(`${context} must be a non-empty route parameter name.`);
10
- }
11
- if (!ROUTE_PARAM_NAME_PATTERN.test(normalizedValue)) {
12
- throw new TypeError(
13
- `${context} "${normalizedValue}" is invalid. Use letters, numbers, and underscores only.`
14
- );
15
- }
16
-
17
- return normalizedValue;
18
- }
19
-
20
- function toRouteParamValue(value) {
21
- if (Array.isArray(value)) {
22
- return toRouteParamValue(value[0]);
23
- }
24
- if (value == null) {
25
- return "";
26
- }
27
-
28
- return String(value).trim();
29
- }
30
-
31
- function resolveRouteSourceValue(source = null) {
32
- if (typeof source === "function") {
33
- return source();
34
- }
35
-
36
- return unref(source);
37
- }
38
-
39
- function resolveRouteParamsSource(source = null) {
40
- return asPlainObject(resolveRouteSourceValue(source));
41
- }
42
-
43
- function normalizeRouteParamNameList(value = []) {
44
- const source = Array.isArray(value) ? value : [];
45
- return source
46
- .map((entry) => String(entry || "").trim())
47
- .filter(Boolean);
48
- }
49
-
50
- function resolveRouteParamNamesSource(source = []) {
51
- return normalizeRouteParamNameList(resolveRouteSourceValue(source));
52
- }
53
-
54
- function normalizeRoutePathname(value = "") {
55
- const rawPathname = String(value || "").trim();
56
- const sanitizedPathname = rawPathname.split(/[?#]/u, 1)[0] || "";
57
- if (!sanitizedPathname) {
58
- return "/";
59
- }
60
-
61
- return sanitizedPathname.startsWith("/") ? sanitizedPathname : `/${sanitizedPathname}`;
62
- }
63
-
64
- function resolveRoutePathnameSource(source = "") {
65
- return normalizeRoutePathname(resolveRouteSourceValue(source));
66
- }
67
-
68
- function segmentMatchesParamValue(segment = "", paramValue = "") {
69
- const normalizedSegment = String(segment || "").trim();
70
- const normalizedParamValue = toRouteParamValue(paramValue);
71
- if (!normalizedSegment || !normalizedParamValue) {
72
- return false;
73
- }
74
-
75
- const encodedParamValue = encodeURIComponent(normalizedParamValue);
76
- if (normalizedSegment === encodedParamValue) {
77
- return true;
78
- }
79
-
80
- try {
81
- return decodeURIComponent(normalizedSegment) === normalizedParamValue;
82
- } catch {
83
- return false;
84
- }
85
- }
86
-
87
- function findRouteParamSegmentIndex(segments = [], paramValue = "", fromIndex = 0) {
88
- const source = Array.isArray(segments) ? segments : [];
89
- const cursor = Number.isInteger(fromIndex) && fromIndex > 0 ? fromIndex : 0;
90
- for (let index = cursor; index < source.length; index += 1) {
91
- if (segmentMatchesParamValue(source[index], paramValue)) {
92
- return index;
93
- }
94
- }
95
- return -1;
96
- }
97
-
98
- function normalizePathPrefix(segments = [], endIndex = -1) {
99
- const source = Array.isArray(segments) ? segments : [];
100
- if (!Number.isInteger(endIndex) || endIndex < 0) {
101
- return "/";
102
- }
103
- return `/${source.slice(0, endIndex + 1).join("/")}`;
104
- }
105
-
106
- function resolveAnchorEndIndex(segmentIndex = -1, totalSegments = 0, anchorMode = "at") {
107
- const normalizedSegmentIndex = Number.isInteger(segmentIndex) ? segmentIndex : -1;
108
- if (normalizedSegmentIndex < 0) {
109
- return -1;
110
- }
111
-
112
- const normalizedTotalSegments = Number.isInteger(totalSegments) && totalSegments > 0 ? totalSegments : 0;
113
- const normalizedMode = String(anchorMode || "at").trim().toLowerCase();
114
- if (normalizedMode === "before") {
115
- return normalizedSegmentIndex - 1;
116
- }
117
- if (normalizedMode === "after") {
118
- return normalizedTotalSegments > 0
119
- ? Math.min(normalizedSegmentIndex + 1, normalizedTotalSegments - 1)
120
- : normalizedSegmentIndex + 1;
121
- }
122
-
123
- return normalizedSegmentIndex;
124
- }
125
-
126
- function resolveScopedRoutePathname({
127
- currentPathname = "/",
128
- params = {},
129
- orderedParamNames = [],
130
- anchorParamName = "",
131
- anchorParamValue = "",
132
- anchorMode = "at"
133
- } = {}) {
134
- const normalizedCurrentPathname = resolveRoutePathnameSource(currentPathname);
135
- const normalizedAnchorParamName = String(anchorParamName || "").trim();
136
- if (!normalizedAnchorParamName) {
137
- return normalizedCurrentPathname;
138
- }
139
-
140
- const sourceParams = asPlainObject(params);
141
- const segments = normalizedCurrentPathname.split("/").filter(Boolean);
142
- if (segments.length < 1) {
143
- return normalizedCurrentPathname;
144
- }
145
-
146
- const paramNames = resolveRouteParamNamesSource(orderedParamNames);
147
- let cursor = 0;
148
- for (const paramName of paramNames) {
149
- const segmentIndex = findRouteParamSegmentIndex(segments, sourceParams[paramName], cursor);
150
- if (segmentIndex < 0) {
151
- continue;
152
- }
153
-
154
- if (paramName === normalizedAnchorParamName) {
155
- const endIndex = resolveAnchorEndIndex(segmentIndex, segments.length, anchorMode);
156
- return normalizePathPrefix(segments, endIndex);
157
- }
158
-
159
- cursor = segmentIndex + 1;
160
- }
161
-
162
- const fallbackAnchorValue = toRouteParamValue(anchorParamValue) ||
163
- toRouteParamValue(sourceParams[normalizedAnchorParamName]);
164
- if (!fallbackAnchorValue) {
165
- return normalizedCurrentPathname;
166
- }
167
-
168
- const fallbackSegmentIndex = findRouteParamSegmentIndex(segments, fallbackAnchorValue, 0);
169
- if (fallbackSegmentIndex < 0) {
170
- return normalizedCurrentPathname;
171
- }
172
-
173
- const fallbackEndIndex = resolveAnchorEndIndex(fallbackSegmentIndex, segments.length, anchorMode);
174
- return normalizePathPrefix(segments, fallbackEndIndex);
175
- }
176
-
177
- function resolveRouteTemplatePath(routeTemplate = "", params = {}) {
178
- const normalizedTemplate = String(routeTemplate || "").trim();
179
- if (!normalizedTemplate) {
180
- return "";
181
- }
182
-
183
- const source = asPlainObject(params);
184
- const missingParams = [];
185
- const resolvedPath = normalizedTemplate.replace(/:([A-Za-z][A-Za-z0-9_]*)/g, (_, key) => {
186
- const value = toRouteParamValue(source[key]);
187
- if (!value) {
188
- missingParams.push(key);
189
- return `:${key}`;
190
- }
191
-
192
- return encodeURIComponent(value);
193
- });
194
-
195
- if (missingParams.length > 0) {
196
- return "";
197
- }
198
-
199
- return resolvedPath;
200
- }
201
-
202
- function resolveRouteTemplateLocation(routeTemplate = "", { params = {}, currentPathname = "/" } = {}) {
203
- const resolvedTemplatePath = resolveRouteTemplatePath(routeTemplate, params);
204
- if (!resolvedTemplatePath) {
205
- return "";
206
- }
207
- if (resolvedTemplatePath.startsWith("/")) {
208
- return resolvedTemplatePath;
209
- }
210
-
211
- const normalizedCurrentPathname = resolveRoutePathnameSource(currentPathname);
212
- const basePathname = normalizedCurrentPathname.endsWith("/")
213
- ? normalizedCurrentPathname
214
- : `${normalizedCurrentPathname}/`;
215
- const resolvedPathname = new URL(resolvedTemplatePath, `https://jskit.local${basePathname}`).pathname;
216
- if (resolvedPathname.length > 1 && resolvedPathname.endsWith("/")) {
217
- return resolvedPathname.slice(0, -1);
218
- }
219
-
220
- return resolvedPathname;
221
- }
222
-
223
- function extractRouteParamNames(pathTemplate = "") {
224
- const normalizedTemplate = String(pathTemplate || "").trim();
225
- if (!normalizedTemplate) {
226
- return [];
227
- }
228
-
229
- const names = [];
230
- const seen = new Set();
231
- const pattern = /:([A-Za-z][A-Za-z0-9_]*)/g;
232
- let match = null;
233
- while ((match = pattern.exec(normalizedTemplate)) != null) {
234
- const name = String(match[1] || "").trim();
235
- if (!name || seen.has(name)) {
236
- continue;
237
- }
238
- seen.add(name);
239
- names.push(name);
240
- }
241
-
242
- return names;
243
- }
244
-
245
- function resolveRouteParamNamesInOrder(route = null) {
246
- const sourceRoute = route && typeof route === "object" ? route : {};
247
- const matched = Array.isArray(sourceRoute.matched) ? sourceRoute.matched : [];
248
- const names = [];
249
- const seen = new Set();
250
-
251
- for (const entry of matched) {
252
- const entryPath = String(entry?.path || "").trim();
253
- if (!entryPath) {
254
- continue;
255
- }
256
- for (const name of extractRouteParamNames(entryPath)) {
257
- if (seen.has(name)) {
258
- continue;
259
- }
260
- seen.add(name);
261
- names.push(name);
262
- }
263
- }
264
-
265
- if (names.length > 0) {
266
- return names;
267
- }
268
-
269
- return Object.keys(asPlainObject(sourceRoute.params))
270
- .map((entry) => String(entry || "").trim())
271
- .filter(Boolean);
272
- }
273
-
274
- export {
275
- normalizeRouteParamName,
276
- toRouteParamValue,
277
- resolveRouteParamsSource,
278
- resolveRouteParamNamesSource,
279
- resolveRoutePathnameSource,
280
- resolveScopedRoutePathname,
281
- resolveRouteTemplatePath,
282
- resolveRouteTemplateLocation,
283
- extractRouteParamNames,
284
- resolveRouteParamNamesInOrder
285
- };