vanilla-jui 1.7.1 → 1.7.2
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.ts +39 -20
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
- package/src/components/accordion.ts +6 -12
- package/src/components/flow.ts +17 -26
- package/src/components/form.ts +11 -28
- package/src/components/menu.ts +7 -13
- package/src/components/modal.ts +40 -26
- package/src/components/offcanvas.ts +6 -12
- package/src/components/pagination.ts +10 -24
- package/src/components/swiper.ts +7 -13
- package/src/components/tabs.ts +6 -12
- package/src/components/toc.ts +5 -8
- package/src/index.ts +4 -1
- package/src/primitives/drop.ts +5 -8
- package/src/primitives/parabola.ts +6 -12
- package/src/primitives/popup.ts +3 -3
- package/src/primitives/sticky.ts +3 -3
- package/src/primitives/theme.ts +29 -14
- package/src/primitives/toast.ts +17 -12
- package/src/primitives/tooltip.ts +5 -19
- package/src/utilities/config.ts +158 -0
- package/src/utilities/id.ts +109 -108
- package/src/utilities/merge.ts +97 -0
- package/src/utilities/types.ts +3 -82
- package/src/utilities/validator.ts +6 -17
|
@@ -3,7 +3,7 @@ import { insert, jsx } from 'vanilla-signal';
|
|
|
3
3
|
import { type DOMReference, resolveElement } from '../utilities/dom.ts';
|
|
4
4
|
import { randomId } from '../utilities/id.ts';
|
|
5
5
|
import { timer } from '../utilities/timer.ts';
|
|
6
|
-
import { type
|
|
6
|
+
import { type ConfigSchema, resolveConfig } from '../utilities/config.ts';
|
|
7
7
|
|
|
8
8
|
type ParabolaDirection =
|
|
9
9
|
| 'center'
|
|
@@ -81,10 +81,7 @@ const PARABOLA_PROPS_SCHEMA = {
|
|
|
81
81
|
ball: {
|
|
82
82
|
default: DEFAULT_BALL,
|
|
83
83
|
type: 'plainObject',
|
|
84
|
-
|
|
85
|
-
...DEFAULT_BALL,
|
|
86
|
-
...(value && typeof value === 'object' ? value : {}),
|
|
87
|
-
}),
|
|
84
|
+
merge: 'shallow',
|
|
88
85
|
shape: {
|
|
89
86
|
color: 'string',
|
|
90
87
|
size: 'string',
|
|
@@ -92,11 +89,8 @@ const PARABOLA_PROPS_SCHEMA = {
|
|
|
92
89
|
},
|
|
93
90
|
className: {
|
|
94
91
|
default: DEFAULT_CLASS_NAMES,
|
|
95
|
-
type: '
|
|
96
|
-
|
|
97
|
-
...DEFAULT_CLASS_NAMES,
|
|
98
|
-
...(value && typeof value === 'object' ? value : {}),
|
|
99
|
-
}),
|
|
92
|
+
type: 'plainObject',
|
|
93
|
+
merge: 'shallow',
|
|
100
94
|
},
|
|
101
95
|
from: { default: null, ...ELEMENT_REF_RULE },
|
|
102
96
|
to: { default: null, ...ELEMENT_REF_RULE },
|
|
@@ -108,10 +102,10 @@ const PARABOLA_PROPS_SCHEMA = {
|
|
|
108
102
|
showDelay: { default: 0, type: 'number' },
|
|
109
103
|
onShow: { default: null, types: ['function', 'null'] },
|
|
110
104
|
onHidden: { default: null, types: ['function', 'null'] },
|
|
111
|
-
} satisfies
|
|
105
|
+
} satisfies ConfigSchema<ParabolaProps>;
|
|
112
106
|
|
|
113
107
|
function normalizeProps(input: ParabolaProps): ResolvedParabolaProps {
|
|
114
|
-
const props =
|
|
108
|
+
const props = resolveConfig(input, PARABOLA_PROPS_SCHEMA, 'Parabola.props');
|
|
115
109
|
return {
|
|
116
110
|
ball: props.ball as ParabolaBallProps,
|
|
117
111
|
className: props.className as ParabolaClassNames,
|
package/src/primitives/popup.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ElementProps, jsx } from 'vanilla-signal';
|
|
2
2
|
|
|
3
3
|
import { asRenderable, type RenderableContent } from '../utilities/dom.ts';
|
|
4
|
-
import { type
|
|
4
|
+
import { type ConfigSchema, resolveConfig } from '../utilities/config.ts';
|
|
5
5
|
|
|
6
6
|
export interface PopupProps extends Record<string, unknown> {
|
|
7
7
|
className?: string;
|
|
@@ -28,10 +28,10 @@ const POPUP_PROPS_SCHEMA = {
|
|
|
28
28
|
default: '',
|
|
29
29
|
type: 'renderable',
|
|
30
30
|
},
|
|
31
|
-
} satisfies
|
|
31
|
+
} satisfies ConfigSchema<PopupProps>;
|
|
32
32
|
|
|
33
33
|
function normalizeProps(input: PopupProps): ResolvedPopupProps {
|
|
34
|
-
const props =
|
|
34
|
+
const props = resolveConfig(input, POPUP_PROPS_SCHEMA, 'Popup');
|
|
35
35
|
|
|
36
36
|
return {
|
|
37
37
|
className: props.className as string,
|
package/src/primitives/sticky.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createDeepStore, flushSync } from 'vanilla-signal';
|
|
2
2
|
import { randomId } from '../utilities/id.ts';
|
|
3
3
|
import { type DOMReference, all, requireContainer } from '../utilities/dom.ts';
|
|
4
|
-
import { type
|
|
4
|
+
import { type ConfigSchema, resolveConfig } from '../utilities/config.ts';
|
|
5
5
|
|
|
6
6
|
type StickyOverflow = 'destroy' | 'ignore';
|
|
7
7
|
|
|
@@ -91,10 +91,10 @@ const STICKY_PROPS_SCHEMA = {
|
|
|
91
91
|
},
|
|
92
92
|
reactive: { default: false, type: 'boolean' },
|
|
93
93
|
onReBuild: { default: null, types: ['function', 'null'] },
|
|
94
|
-
} satisfies
|
|
94
|
+
} satisfies ConfigSchema<StickyProps>;
|
|
95
95
|
|
|
96
96
|
function normalizeProps(input: StickyProps): ResolvedStickyProps {
|
|
97
|
-
const props =
|
|
97
|
+
const props = resolveConfig(input, STICKY_PROPS_SCHEMA, 'Sticky.props');
|
|
98
98
|
return {
|
|
99
99
|
target: props.target as DOMReference,
|
|
100
100
|
parent: props.parent as DOMReference,
|
package/src/primitives/theme.ts
CHANGED
|
@@ -11,6 +11,8 @@ import { translate } from '../utilities/locale.ts';
|
|
|
11
11
|
import { all, joinClasses } from '../utilities/dom.ts';
|
|
12
12
|
import { createEventManager } from '../utilities/events.ts';
|
|
13
13
|
import { isPlainObject } from '../utilities/object.ts';
|
|
14
|
+
import { type ConfigSchema, resolveConfig } from '../utilities/config.ts';
|
|
15
|
+
import { mergeShallowConfig } from '../utilities/merge.ts';
|
|
14
16
|
|
|
15
17
|
export type ThemeConfigKey = 'mode' | 'theme' | 'radius' | 'shadow' | 'font';
|
|
16
18
|
|
|
@@ -101,16 +103,26 @@ const THEME_CLASS_PREFIX: Record<Exclude<ThemeConfigKey, 'mode'>, string> = {
|
|
|
101
103
|
font: 'j-font-',
|
|
102
104
|
};
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
106
|
+
const THEME_OPTIONS_SCHEMA = {
|
|
107
|
+
mode: { default: DEFAULT_OPTIONS.mode, type: 'string' },
|
|
108
|
+
theme: { default: DEFAULT_OPTIONS.theme, type: 'string' },
|
|
109
|
+
radius: { default: DEFAULT_OPTIONS.radius, type: 'string' },
|
|
110
|
+
shadow: { default: DEFAULT_OPTIONS.shadow, type: 'string' },
|
|
111
|
+
font: { default: DEFAULT_OPTIONS.font, type: 'string' },
|
|
112
|
+
key: { default: DEFAULT_OPTIONS.key, type: 'string' },
|
|
113
|
+
className: {
|
|
114
|
+
default: DEFAULT_CLASS_NAMES,
|
|
115
|
+
type: 'plainObject',
|
|
116
|
+
merge: 'shallow',
|
|
117
|
+
},
|
|
118
|
+
} satisfies ConfigSchema<ThemeOptions>;
|
|
107
119
|
|
|
108
120
|
function normalizeOptions(options: ThemeOptions = {}): ThemeResolvedOptions {
|
|
109
|
-
return
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
return resolveConfig(
|
|
122
|
+
options,
|
|
123
|
+
THEME_OPTIONS_SCHEMA,
|
|
124
|
+
'Theme.options'
|
|
125
|
+
) as unknown as ThemeResolvedOptions;
|
|
114
126
|
}
|
|
115
127
|
|
|
116
128
|
function isThemeConfigKey(value: string | undefined): value is ThemeConfigKey {
|
|
@@ -340,14 +352,17 @@ export function createTheme(options: ThemeOptions = {}): ThemeInstance {
|
|
|
340
352
|
return panel;
|
|
341
353
|
};
|
|
342
354
|
const setConfig = (newConfig: ThemeOptions): void => {
|
|
355
|
+
const config = normalizeOptions({
|
|
356
|
+
...props,
|
|
357
|
+
...newConfig,
|
|
358
|
+
className: mergeShallowConfig(
|
|
359
|
+
props.className,
|
|
360
|
+
newConfig.className ?? {}
|
|
361
|
+
) as ThemeClassNames,
|
|
362
|
+
});
|
|
343
363
|
runtime.configVersion += 1;
|
|
344
364
|
flushSync(() => {
|
|
345
|
-
Object.assign(props,
|
|
346
|
-
className: mergeClassNames({
|
|
347
|
-
...props.className,
|
|
348
|
-
...newConfig.className,
|
|
349
|
-
}),
|
|
350
|
-
});
|
|
365
|
+
Object.assign(props, config);
|
|
351
366
|
});
|
|
352
367
|
saveConfig();
|
|
353
368
|
};
|
package/src/primitives/toast.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { createLoading } from '../primitives/loading.ts';
|
|
|
12
12
|
import { joinClasses, q } from '../utilities/dom.ts';
|
|
13
13
|
import { listen } from '../utilities/events.ts';
|
|
14
14
|
import { randomId } from '../utilities/id.ts';
|
|
15
|
+
import { mergeShallowConfig } from '../utilities/merge.ts';
|
|
15
16
|
import { timer } from '../utilities/timer.ts';
|
|
16
17
|
import { validateParam } from '../utilities/types.ts';
|
|
17
18
|
|
|
@@ -98,14 +99,6 @@ const operations = new Map<HTMLElement, number>();
|
|
|
98
99
|
const singletonToasts = new Map<'show' | 'confirm', HTMLElement>();
|
|
99
100
|
let classNames = DEFAULT_CLASS_NAMES;
|
|
100
101
|
|
|
101
|
-
function mergeClassNames(value?: ToastClassNameConfig): ToastClassNames {
|
|
102
|
-
return { ...DEFAULT_CLASS_NAMES, ...value };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function resolveClassNames(options?: ToastClassNameOptions): ToastClassNames {
|
|
106
|
-
return mergeClassNames({ ...classNames, ...options?.className });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
102
|
function addToastDisposer(element: HTMLElement, dispose: () => void): void {
|
|
110
103
|
const current = disposers.get(element);
|
|
111
104
|
disposers.set(element, () => {
|
|
@@ -378,7 +371,10 @@ function show(message = '', options: ToastOptions = {}): HTMLElement {
|
|
|
378
371
|
validateParam('duration', duration, TOAST_DURATION_RULE, 'Toast.show');
|
|
379
372
|
validateParam('theme', theme, TOAST_THEME_RULE, 'Toast.show');
|
|
380
373
|
|
|
381
|
-
const names =
|
|
374
|
+
const names = mergeShallowConfig(
|
|
375
|
+
classNames,
|
|
376
|
+
options.className ?? {}
|
|
377
|
+
) as ToastClassNames;
|
|
382
378
|
const id = randomId();
|
|
383
379
|
const iconElement = jsx('span', {
|
|
384
380
|
className: names.icon,
|
|
@@ -426,7 +422,10 @@ function lite(
|
|
|
426
422
|
validateParam('message', message, 'string', 'Toast.lite');
|
|
427
423
|
validateParam('duration', duration, LITE_DURATION_RULE, 'Toast.lite');
|
|
428
424
|
|
|
429
|
-
const names =
|
|
425
|
+
const names = mergeShallowConfig(
|
|
426
|
+
classNames,
|
|
427
|
+
className ?? {}
|
|
428
|
+
) as ToastClassNames;
|
|
430
429
|
const previous = q<HTMLElement>('[data-toast-lite]');
|
|
431
430
|
if (previous) {
|
|
432
431
|
cancelToastTimers(previous.dataset.toast || '');
|
|
@@ -457,7 +456,10 @@ function confirm(message = '', props: ToastConfirmProps = {}): HTMLElement {
|
|
|
457
456
|
const theme = props.theme || 'info';
|
|
458
457
|
validateParam('once', once, 'boolean', 'Toast.confirm');
|
|
459
458
|
validateParam('theme', theme, TOAST_THEME_RULE, 'Toast.confirm');
|
|
460
|
-
const names =
|
|
459
|
+
const names = mergeShallowConfig(
|
|
460
|
+
classNames,
|
|
461
|
+
props.className ?? {}
|
|
462
|
+
) as ToastClassNames;
|
|
461
463
|
const id = randomId();
|
|
462
464
|
const element = jsx('div', {
|
|
463
465
|
className: joinClasses(names.confirm, names[theme]),
|
|
@@ -526,7 +528,10 @@ export const Toast = {
|
|
|
526
528
|
timers,
|
|
527
529
|
disposers,
|
|
528
530
|
configure(options: ToastClassNameOptions = {}): ToastClassNameOptions {
|
|
529
|
-
classNames =
|
|
531
|
+
classNames = mergeShallowConfig(
|
|
532
|
+
DEFAULT_CLASS_NAMES,
|
|
533
|
+
options.className ?? {}
|
|
534
|
+
) as ToastClassNames;
|
|
530
535
|
return { className: classNames };
|
|
531
536
|
},
|
|
532
537
|
show,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from 'vanilla-signal';
|
|
2
2
|
|
|
3
3
|
import { type DOMReference, joinClasses } from '../utilities/dom.ts';
|
|
4
|
-
import { type
|
|
4
|
+
import { type ConfigSchema, resolveConfig } from '../utilities/config.ts';
|
|
5
5
|
import { createDrop } from './drop.ts';
|
|
6
6
|
|
|
7
7
|
type DropInstance = ReturnType<typeof createDrop>;
|
|
@@ -102,20 +102,6 @@ const DEFAULT_CLASS_NAMES: TooltipClassNames = {
|
|
|
102
102
|
},
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
-
function normalizeClassNames(value: unknown): TooltipClassNames {
|
|
106
|
-
const input = value && typeof value === 'object' ? value : {};
|
|
107
|
-
const ui =
|
|
108
|
-
'ui' in input && input.ui && typeof input.ui === 'object' ? input.ui : {};
|
|
109
|
-
return {
|
|
110
|
-
...DEFAULT_CLASS_NAMES,
|
|
111
|
-
...input,
|
|
112
|
-
ui: {
|
|
113
|
-
...DEFAULT_CLASS_NAMES.ui,
|
|
114
|
-
...ui,
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
105
|
const TOOLTIP_OPTIONS_SCHEMA = {
|
|
120
106
|
name: { default: null, types: ['string', 'null'] },
|
|
121
107
|
mode: { default: 'hover', type: 'string', enum: ['hover', 'click'] },
|
|
@@ -155,18 +141,18 @@ const TOOLTIP_OPTIONS_SCHEMA = {
|
|
|
155
141
|
},
|
|
156
142
|
className: {
|
|
157
143
|
default: DEFAULT_CLASS_NAMES,
|
|
158
|
-
type: '
|
|
159
|
-
|
|
144
|
+
type: 'plainObject',
|
|
145
|
+
merge: 'deep',
|
|
160
146
|
},
|
|
161
147
|
id: { default: null, types: ['string', 'null'] },
|
|
162
148
|
delay: { default: 100, types: ['number', 'object'] },
|
|
163
149
|
hoverIntent: { default: true, type: 'boolean' },
|
|
164
150
|
onShown: { default: null, types: ['function', 'null'] },
|
|
165
151
|
onHidden: { default: null, types: ['function', 'null'] },
|
|
166
|
-
} satisfies
|
|
152
|
+
} satisfies ConfigSchema<TooltipProps>;
|
|
167
153
|
|
|
168
154
|
function normalizeProps(input: TooltipProps): ResolvedTooltipProps {
|
|
169
|
-
const props =
|
|
155
|
+
const props = resolveConfig(input, TOOLTIP_OPTIONS_SCHEMA, 'Tooltip.props');
|
|
170
156
|
return {
|
|
171
157
|
name: props.name as string | null,
|
|
172
158
|
mode: props.mode as DropMode,
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { type ParamRule, type ParamRuleInput, validateParam } from './types.ts';
|
|
2
|
+
import {
|
|
3
|
+
type MergeStrategy,
|
|
4
|
+
cloneConfigValue,
|
|
5
|
+
mergeConfigValue,
|
|
6
|
+
} from './merge.ts';
|
|
7
|
+
import { isPlainObject } from './object.ts';
|
|
8
|
+
|
|
9
|
+
type LooseRecord = Record<string, unknown>;
|
|
10
|
+
type ConfigTypeRule = string | readonly string[];
|
|
11
|
+
|
|
12
|
+
export interface ConfigNormalizeContext<
|
|
13
|
+
TInput extends LooseRecord = LooseRecord,
|
|
14
|
+
> {
|
|
15
|
+
key: string;
|
|
16
|
+
path: string;
|
|
17
|
+
input: TInput;
|
|
18
|
+
options: LooseRecord;
|
|
19
|
+
schema: ConfigSchema<TInput>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ConfigRule<
|
|
23
|
+
TInput extends LooseRecord = LooseRecord,
|
|
24
|
+
> extends Omit<ParamRule<TInput>, 'normalize' | 'shape'> {
|
|
25
|
+
defaultFactory?: () => unknown;
|
|
26
|
+
merge?: MergeStrategy;
|
|
27
|
+
schema?: ConfigSchema;
|
|
28
|
+
normalize?: (
|
|
29
|
+
value: unknown,
|
|
30
|
+
context: ConfigNormalizeContext<TInput>
|
|
31
|
+
) => unknown;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ConfigRuleInput<TInput extends LooseRecord = LooseRecord> =
|
|
35
|
+
| ConfigTypeRule
|
|
36
|
+
| ConfigRule<TInput>;
|
|
37
|
+
|
|
38
|
+
export type ConfigSchema<TInput extends LooseRecord = LooseRecord> = Record<
|
|
39
|
+
string,
|
|
40
|
+
ConfigRuleInput<TInput>
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export type ResolvedConfig<TSchema extends object> = LooseRecord & {
|
|
44
|
+
[Key in keyof TSchema]: unknown;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function normalizeConfigRule<TInput extends LooseRecord>(
|
|
48
|
+
rule: ConfigRuleInput<TInput> = {}
|
|
49
|
+
): ConfigRule<TInput> {
|
|
50
|
+
if (typeof rule === 'string' || Array.isArray(rule)) return { type: rule };
|
|
51
|
+
if (!rule || typeof rule !== 'object') return {};
|
|
52
|
+
return rule as ConfigRule<TInput>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function resolveConfigDefault<TInput extends LooseRecord>(
|
|
56
|
+
rule: ConfigRule<TInput>
|
|
57
|
+
): unknown {
|
|
58
|
+
if (typeof rule.defaultFactory === 'function') {
|
|
59
|
+
return cloneConfigValue(rule.defaultFactory());
|
|
60
|
+
}
|
|
61
|
+
if (Object.hasOwn(rule, 'default')) {
|
|
62
|
+
return cloneConfigValue(rule.default);
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isInputMissing(source: LooseRecord, key: string): boolean {
|
|
68
|
+
return !Object.hasOwn(source, key) || source[key] === undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveConfigValue<TInput extends LooseRecord>(
|
|
72
|
+
key: string,
|
|
73
|
+
rule: ConfigRule<TInput>,
|
|
74
|
+
source: TInput,
|
|
75
|
+
namespace: string
|
|
76
|
+
): unknown {
|
|
77
|
+
const path = namespace ? `${namespace}.${key}` : key;
|
|
78
|
+
const defaultValue = resolveConfigDefault(rule);
|
|
79
|
+
const value = isInputMissing(source, key)
|
|
80
|
+
? defaultValue
|
|
81
|
+
: mergeConfigValue(defaultValue, source[key], rule.merge, { key, path });
|
|
82
|
+
|
|
83
|
+
return rule.schema && (value === undefined || isPlainObject(value))
|
|
84
|
+
? resolveConfig(value as LooseRecord | undefined, rule.schema, path)
|
|
85
|
+
: value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function validateConfigValue<TInput extends LooseRecord>(
|
|
89
|
+
key: string,
|
|
90
|
+
value: unknown,
|
|
91
|
+
rule: ConfigRule<TInput>,
|
|
92
|
+
namespace: string
|
|
93
|
+
): void {
|
|
94
|
+
const validationRule: ParamRuleInput<TInput> = rule as ParamRule<TInput>;
|
|
95
|
+
validateParam(key, value, validationRule, namespace);
|
|
96
|
+
|
|
97
|
+
if (!rule.schema || !isPlainObject(value)) return;
|
|
98
|
+
|
|
99
|
+
const childNamespace = namespace ? `${namespace}.${key}` : key;
|
|
100
|
+
const valueRecord = value as LooseRecord;
|
|
101
|
+
for (const [childKey, childRule] of Object.entries(rule.schema)) {
|
|
102
|
+
validateConfigValue(
|
|
103
|
+
childKey,
|
|
104
|
+
valueRecord[childKey],
|
|
105
|
+
normalizeConfigRule(childRule),
|
|
106
|
+
childNamespace
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function resolveConfig<
|
|
112
|
+
TInput extends LooseRecord,
|
|
113
|
+
TSchema extends ConfigSchema<TInput>,
|
|
114
|
+
>(
|
|
115
|
+
input: TInput | null | undefined = {} as TInput,
|
|
116
|
+
schema: TSchema = {} as TSchema,
|
|
117
|
+
namespace = 'Config'
|
|
118
|
+
): ResolvedConfig<TSchema> {
|
|
119
|
+
const source = input == null ? {} : input;
|
|
120
|
+
if (typeof source !== 'object' || Array.isArray(source)) {
|
|
121
|
+
throw new Error(`${namespace} expects object.`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const sourceRecord = source as TInput;
|
|
125
|
+
const resolved: LooseRecord = {};
|
|
126
|
+
const entries = Object.entries(schema || {}) as Array<
|
|
127
|
+
[string, ConfigRuleInput<TInput>]
|
|
128
|
+
>;
|
|
129
|
+
|
|
130
|
+
for (const [key, rawRule] of entries) {
|
|
131
|
+
const rule = normalizeConfigRule<TInput>(rawRule);
|
|
132
|
+
resolved[key] = resolveConfigValue(key, rule, sourceRecord, namespace);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const [key, rawRule] of entries) {
|
|
136
|
+
const rule = normalizeConfigRule<TInput>(rawRule);
|
|
137
|
+
if (typeof rule.normalize === 'function') {
|
|
138
|
+
resolved[key] = rule.normalize(resolved[key], {
|
|
139
|
+
key,
|
|
140
|
+
path: namespace ? `${namespace}.${key}` : key,
|
|
141
|
+
input: sourceRecord,
|
|
142
|
+
options: resolved,
|
|
143
|
+
schema,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const [key, rule] of entries) {
|
|
149
|
+
validateConfigValue(
|
|
150
|
+
key,
|
|
151
|
+
resolved[key],
|
|
152
|
+
normalizeConfigRule<TInput>(rule),
|
|
153
|
+
namespace
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return resolved as ResolvedConfig<TSchema>;
|
|
158
|
+
}
|
package/src/utilities/id.ts
CHANGED
|
@@ -73,113 +73,113 @@ type QueryParamValue =
|
|
|
73
73
|
*/
|
|
74
74
|
type QueryParams = Record<string, QueryParamValue>;
|
|
75
75
|
|
|
76
|
-
const SHA256_K = new Uint32Array([
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
]);
|
|
89
|
-
|
|
90
|
-
const SHA256_INITIAL = new Uint32Array([
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
]);
|
|
94
|
-
|
|
95
|
-
function rotateRight(value: number, bits: number): number {
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function sha256Fallback(input: Uint8Array): Uint8Array {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
76
|
+
// const SHA256_K = new Uint32Array([
|
|
77
|
+
// 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
|
78
|
+
// 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
|
79
|
+
// 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
80
|
+
// 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
81
|
+
// 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
|
82
|
+
// 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
83
|
+
// 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
|
84
|
+
// 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
85
|
+
// 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
86
|
+
// 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
|
87
|
+
// 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
88
|
+
// ]);
|
|
89
|
+
|
|
90
|
+
// const SHA256_INITIAL = new Uint32Array([
|
|
91
|
+
// 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
|
|
92
|
+
// 0x1f83d9ab, 0x5be0cd19,
|
|
93
|
+
// ]);
|
|
94
|
+
|
|
95
|
+
// function rotateRight(value: number, bits: number): number {
|
|
96
|
+
// return (value >>> bits) | (value << (32 - bits));
|
|
97
|
+
// }
|
|
98
|
+
|
|
99
|
+
// function sha256Fallback(input: Uint8Array): Uint8Array {
|
|
100
|
+
// const message = new Uint8Array(Math.ceil((input.length + 9) / 64) * 64);
|
|
101
|
+
// message.set(input);
|
|
102
|
+
// message[input.length] = 0x80;
|
|
103
|
+
|
|
104
|
+
// const bitLength = BigInt(input.length) * 8n;
|
|
105
|
+
// for (let i = 0; i < 8; i += 1) {
|
|
106
|
+
// message[message.length - 1 - i] = Number(
|
|
107
|
+
// (bitLength >> BigInt(i * 8)) & 0xffn
|
|
108
|
+
// );
|
|
109
|
+
// }
|
|
110
|
+
|
|
111
|
+
// const hash = new Uint32Array(SHA256_INITIAL);
|
|
112
|
+
// const words = new Uint32Array(64);
|
|
113
|
+
|
|
114
|
+
// for (let offset = 0; offset < message.length; offset += 64) {
|
|
115
|
+
// for (let i = 0; i < 16; i += 1) {
|
|
116
|
+
// const index = offset + i * 4;
|
|
117
|
+
// words[i] =
|
|
118
|
+
// ((message[index] << 24) |
|
|
119
|
+
// (message[index + 1] << 16) |
|
|
120
|
+
// (message[index + 2] << 8) |
|
|
121
|
+
// message[index + 3]) >>>
|
|
122
|
+
// 0;
|
|
123
|
+
// }
|
|
124
|
+
|
|
125
|
+
// for (let i = 16; i < 64; i += 1) {
|
|
126
|
+
// const s0 =
|
|
127
|
+
// rotateRight(words[i - 15], 7) ^
|
|
128
|
+
// rotateRight(words[i - 15], 18) ^
|
|
129
|
+
// (words[i - 15] >>> 3);
|
|
130
|
+
// const s1 =
|
|
131
|
+
// rotateRight(words[i - 2], 17) ^
|
|
132
|
+
// rotateRight(words[i - 2], 19) ^
|
|
133
|
+
// (words[i - 2] >>> 10);
|
|
134
|
+
// words[i] = (words[i - 16] + s0 + words[i - 7] + s1) >>> 0;
|
|
135
|
+
// }
|
|
136
|
+
|
|
137
|
+
// let a = hash[0];
|
|
138
|
+
// let b = hash[1];
|
|
139
|
+
// let c = hash[2];
|
|
140
|
+
// let d = hash[3];
|
|
141
|
+
// let e = hash[4];
|
|
142
|
+
// let f = hash[5];
|
|
143
|
+
// let g = hash[6];
|
|
144
|
+
// let h = hash[7];
|
|
145
|
+
|
|
146
|
+
// for (let i = 0; i < 64; i += 1) {
|
|
147
|
+
// const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
|
|
148
|
+
// const ch = (e & f) ^ (~e & g);
|
|
149
|
+
// const temp1 = (h + s1 + ch + SHA256_K[i] + words[i]) >>> 0;
|
|
150
|
+
// const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
|
|
151
|
+
// const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
152
|
+
// const temp2 = (s0 + maj) >>> 0;
|
|
153
|
+
|
|
154
|
+
// h = g;
|
|
155
|
+
// g = f;
|
|
156
|
+
// f = e;
|
|
157
|
+
// e = (d + temp1) >>> 0;
|
|
158
|
+
// d = c;
|
|
159
|
+
// c = b;
|
|
160
|
+
// b = a;
|
|
161
|
+
// a = (temp1 + temp2) >>> 0;
|
|
162
|
+
// }
|
|
163
|
+
|
|
164
|
+
// hash[0] = (hash[0] + a) >>> 0;
|
|
165
|
+
// hash[1] = (hash[1] + b) >>> 0;
|
|
166
|
+
// hash[2] = (hash[2] + c) >>> 0;
|
|
167
|
+
// hash[3] = (hash[3] + d) >>> 0;
|
|
168
|
+
// hash[4] = (hash[4] + e) >>> 0;
|
|
169
|
+
// hash[5] = (hash[5] + f) >>> 0;
|
|
170
|
+
// hash[6] = (hash[6] + g) >>> 0;
|
|
171
|
+
// hash[7] = (hash[7] + h) >>> 0;
|
|
172
|
+
// }
|
|
173
|
+
|
|
174
|
+
// const output = new Uint8Array(32);
|
|
175
|
+
// for (let i = 0; i < hash.length; i += 1) {
|
|
176
|
+
// output[i * 4] = hash[i] >>> 24;
|
|
177
|
+
// output[i * 4 + 1] = hash[i] >>> 16;
|
|
178
|
+
// output[i * 4 + 2] = hash[i] >>> 8;
|
|
179
|
+
// output[i * 4 + 3] = hash[i];
|
|
180
|
+
// }
|
|
181
|
+
// return output;
|
|
182
|
+
// }
|
|
183
183
|
|
|
184
184
|
async function sha256(input: Uint8Array): Promise<Uint8Array> {
|
|
185
185
|
const subtle = globalThis.crypto?.subtle;
|
|
@@ -188,7 +188,8 @@ async function sha256(input: Uint8Array): Promise<Uint8Array> {
|
|
|
188
188
|
new Uint8Array(source).set(input);
|
|
189
189
|
return new Uint8Array(await subtle.digest('SHA-256', source));
|
|
190
190
|
}
|
|
191
|
-
return sha256Fallback(input);
|
|
191
|
+
// return sha256Fallback(input);
|
|
192
|
+
throw new Error('hashQueryParams only works in secure context.');
|
|
192
193
|
}
|
|
193
194
|
|
|
194
195
|
/**
|