@ktjs/shared 0.19.0
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/LICENSE +21 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.iife.js +183 -0
- package/dist/index.legacy.js +195 -0
- package/dist/index.mjs +160 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 kasukabe tsumugi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
declare const $isArray: (arg: any) => arg is any[];
|
|
2
|
+
declare const $hasOwn: (v: PropertyKey) => boolean;
|
|
3
|
+
declare const $keys: <T>(o: T) => Array<keyof T>;
|
|
4
|
+
declare const $defines: <T>(o: T, properties: PropertyDescriptorMap & ThisType<any>) => T;
|
|
5
|
+
declare const $entries: <T>(o: T) => Array<[keyof T, T[keyof T]]>;
|
|
6
|
+
declare const $isThenable: (o: any) => o is Promise<any>;
|
|
7
|
+
|
|
8
|
+
declare const $throw: (message: string) => never;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
12
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
13
|
+
*/
|
|
14
|
+
declare const $appendChild: <T extends Node>(node: T) => T;
|
|
15
|
+
declare const originAppend: (...nodes: (Node | string)[]) => void;
|
|
16
|
+
declare const $append: typeof originAppend;
|
|
17
|
+
declare const parseStyle: (style: string | Partial<CSSStyleDeclaration> | undefined) => string;
|
|
18
|
+
type ChangeHandler<T = string> = (value: T, ...args: any[]) => void;
|
|
19
|
+
declare const generateHandler: <T = string>(props: any, key: string) => ChangeHandler<T>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Default empty function
|
|
23
|
+
*/
|
|
24
|
+
declare const $emptyFn: (...args: any[]) => any;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalize path by joining parts and ensuring leading slash
|
|
28
|
+
*/
|
|
29
|
+
declare const normalizePath: (...paths: string[]) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Parse query string into object
|
|
32
|
+
*/
|
|
33
|
+
declare const parseQuery: (queryString: string) => Record<string, string>;
|
|
34
|
+
/**
|
|
35
|
+
* Build query string from object
|
|
36
|
+
*/
|
|
37
|
+
declare const buildQuery: (query: Record<string, string>) => string;
|
|
38
|
+
/**
|
|
39
|
+
* Substitute params into path pattern
|
|
40
|
+
* @example '/user/:id' + {id: '123'} => '/user/123'
|
|
41
|
+
*/
|
|
42
|
+
declare const emplaceParams: (path: string, params: Record<string, string>) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Extract dynamic params from path using pattern
|
|
45
|
+
* @example pattern: '/user/:id', path: '/user/123' => {id: '123'}
|
|
46
|
+
*/
|
|
47
|
+
declare const extractParams: (pattern: string, path: string) => Record<string, string> | null;
|
|
48
|
+
|
|
49
|
+
export { $append, $appendChild, $defines, $emptyFn, $entries, $hasOwn, $isArray, $isThenable, $keys, $throw, buildQuery, emplaceParams, extractParams, generateHandler, normalizePath, parseQuery, parseStyle };
|
|
50
|
+
export type { ChangeHandler };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
var __ktjs_shared__ = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Cached native methods for performance optimization
|
|
5
|
+
const $isArray = Array.isArray;
|
|
6
|
+
const $hasOwn = Object.prototype.hasOwnProperty;
|
|
7
|
+
const $keys = Object.keys;
|
|
8
|
+
const $defines = Object.defineProperties;
|
|
9
|
+
const $entries = Object.entries;
|
|
10
|
+
const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
|
|
11
|
+
|
|
12
|
+
// Error handling utilities
|
|
13
|
+
const $throw = (message) => {
|
|
14
|
+
throw new Error('@ktjs/shared: ' + message);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// String manipulation utilities
|
|
18
|
+
/**
|
|
19
|
+
* Default empty function
|
|
20
|
+
*/
|
|
21
|
+
const $emptyFn = (() => true);
|
|
22
|
+
|
|
23
|
+
// DOM manipulation utilities
|
|
24
|
+
/**
|
|
25
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
26
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
27
|
+
*/
|
|
28
|
+
const $appendChild = HTMLElement.prototype.appendChild;
|
|
29
|
+
const originAppend = HTMLElement.prototype.append;
|
|
30
|
+
const $append = // for ie 9/10/11
|
|
31
|
+
typeof originAppend === 'function'
|
|
32
|
+
? originAppend
|
|
33
|
+
: function (...nodes) {
|
|
34
|
+
if (nodes.length < 50) {
|
|
35
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
36
|
+
const node = nodes[i];
|
|
37
|
+
if (typeof node === 'string') {
|
|
38
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
$appendChild.call(this, node);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const fragment = document.createDocumentFragment();
|
|
47
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
48
|
+
const node = nodes[i];
|
|
49
|
+
if (typeof node === 'string') {
|
|
50
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
$appendChild.call(fragment, node);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
$appendChild.call(this, fragment);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
// Style parsing utilities
|
|
60
|
+
const parseStyle = (style) => {
|
|
61
|
+
if (typeof style === 'string') {
|
|
62
|
+
return style;
|
|
63
|
+
}
|
|
64
|
+
if (style && typeof style === 'object') {
|
|
65
|
+
return Object.entries(style)
|
|
66
|
+
.map(([key, value]) => {
|
|
67
|
+
// Convert camelCase to kebab-case
|
|
68
|
+
const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
69
|
+
return `${cssKey}: ${value}`;
|
|
70
|
+
})
|
|
71
|
+
.join('; ');
|
|
72
|
+
}
|
|
73
|
+
return '';
|
|
74
|
+
};
|
|
75
|
+
const generateHandler = (props, key) => {
|
|
76
|
+
const handler = props[key];
|
|
77
|
+
if (typeof handler === 'function') {
|
|
78
|
+
return handler;
|
|
79
|
+
}
|
|
80
|
+
else if (handler && typeof handler === 'object' && handler.isKT) {
|
|
81
|
+
return (value) => (handler.value = value);
|
|
82
|
+
}
|
|
83
|
+
return $emptyFn;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Normalize path by joining parts and ensuring leading slash
|
|
88
|
+
*/
|
|
89
|
+
const normalizePath = (...paths) => {
|
|
90
|
+
const p = paths
|
|
91
|
+
.map((p) => p.split('/'))
|
|
92
|
+
.flat()
|
|
93
|
+
.filter(Boolean);
|
|
94
|
+
return '/' + p.join('/');
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Parse query string into object
|
|
98
|
+
*/
|
|
99
|
+
const parseQuery = (queryString) => {
|
|
100
|
+
const query = {};
|
|
101
|
+
if (!queryString || queryString === '?') {
|
|
102
|
+
return query;
|
|
103
|
+
}
|
|
104
|
+
const params = queryString.replace(/^\?/, '').split('&');
|
|
105
|
+
for (const param of params) {
|
|
106
|
+
const [key, value] = param.split('=');
|
|
107
|
+
if (key) {
|
|
108
|
+
query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return query;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Build query string from object
|
|
115
|
+
*/
|
|
116
|
+
const buildQuery = (query) => {
|
|
117
|
+
const keys = Object.keys(query);
|
|
118
|
+
if (keys.length === 0)
|
|
119
|
+
return '';
|
|
120
|
+
const params = keys.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`).join('&');
|
|
121
|
+
return `?${params}`;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Substitute params into path pattern
|
|
125
|
+
* @example '/user/:id' + {id: '123'} => '/user/123'
|
|
126
|
+
*/
|
|
127
|
+
const emplaceParams = (path, params) => {
|
|
128
|
+
let result = path;
|
|
129
|
+
for (const key in params) {
|
|
130
|
+
result = result.replace(`:${key}`, params[key]);
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Extract dynamic params from path using pattern
|
|
136
|
+
* @example pattern: '/user/:id', path: '/user/123' => {id: '123'}
|
|
137
|
+
*/
|
|
138
|
+
const extractParams = (pattern, path) => {
|
|
139
|
+
const params = {};
|
|
140
|
+
const patternParts = pattern.split('/');
|
|
141
|
+
const pathParts = path.split('/');
|
|
142
|
+
if (patternParts.length !== pathParts.length) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
146
|
+
const patternPart = patternParts[i];
|
|
147
|
+
const pathPart = pathParts[i];
|
|
148
|
+
if (patternPart.startsWith(':')) {
|
|
149
|
+
const paramName = patternPart.slice(1);
|
|
150
|
+
params[paramName] = pathPart;
|
|
151
|
+
}
|
|
152
|
+
else if (patternPart !== pathPart) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return params;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Shared utilities and cached native methods for kt.js framework
|
|
160
|
+
// Re-export all utilities
|
|
161
|
+
Object.defineProperty(window, '@ktjs/shared', { value: '0.19.0' });
|
|
162
|
+
|
|
163
|
+
exports.$append = $append;
|
|
164
|
+
exports.$appendChild = $appendChild;
|
|
165
|
+
exports.$defines = $defines;
|
|
166
|
+
exports.$emptyFn = $emptyFn;
|
|
167
|
+
exports.$entries = $entries;
|
|
168
|
+
exports.$hasOwn = $hasOwn;
|
|
169
|
+
exports.$isArray = $isArray;
|
|
170
|
+
exports.$isThenable = $isThenable;
|
|
171
|
+
exports.$keys = $keys;
|
|
172
|
+
exports.$throw = $throw;
|
|
173
|
+
exports.buildQuery = buildQuery;
|
|
174
|
+
exports.emplaceParams = emplaceParams;
|
|
175
|
+
exports.extractParams = extractParams;
|
|
176
|
+
exports.generateHandler = generateHandler;
|
|
177
|
+
exports.normalizePath = normalizePath;
|
|
178
|
+
exports.parseQuery = parseQuery;
|
|
179
|
+
exports.parseStyle = parseStyle;
|
|
180
|
+
|
|
181
|
+
return exports;
|
|
182
|
+
|
|
183
|
+
})({});
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
var __ktjs_shared__ = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Cached native methods for performance optimization
|
|
5
|
+
var $isArray = Array.isArray;
|
|
6
|
+
var $hasOwn = Object.prototype.hasOwnProperty;
|
|
7
|
+
var $keys = Object.keys;
|
|
8
|
+
var $defines = Object.defineProperties;
|
|
9
|
+
var $entries = Object.entries;
|
|
10
|
+
var $isThenable = function (o) {
|
|
11
|
+
return typeof o === 'object' && o !== null && typeof o.then === 'function';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Error handling utilities
|
|
15
|
+
var $throw = function (message) {
|
|
16
|
+
throw new Error('@ktjs/shared: ' + message);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// String manipulation utilities
|
|
20
|
+
/**
|
|
21
|
+
* Default empty function
|
|
22
|
+
*/
|
|
23
|
+
var $emptyFn = (function () { return true; });
|
|
24
|
+
|
|
25
|
+
// DOM manipulation utilities
|
|
26
|
+
/**
|
|
27
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
28
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
29
|
+
*/
|
|
30
|
+
var $appendChild = HTMLElement.prototype.appendChild;
|
|
31
|
+
var originAppend = HTMLElement.prototype.append;
|
|
32
|
+
var $append = // for ie 9/10/11
|
|
33
|
+
typeof originAppend === 'function'
|
|
34
|
+
? originAppend
|
|
35
|
+
: function () {
|
|
36
|
+
var nodes = [];
|
|
37
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
38
|
+
nodes[_i] = arguments[_i];
|
|
39
|
+
}
|
|
40
|
+
if (nodes.length < 50) {
|
|
41
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
42
|
+
var node = nodes[i];
|
|
43
|
+
if (typeof node === 'string') {
|
|
44
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
$appendChild.call(this, node);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
var fragment = document.createDocumentFragment();
|
|
53
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
54
|
+
var node = nodes[i];
|
|
55
|
+
if (typeof node === 'string') {
|
|
56
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
$appendChild.call(fragment, node);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
$appendChild.call(this, fragment);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
// Style parsing utilities
|
|
66
|
+
var parseStyle = function (style) {
|
|
67
|
+
if (typeof style === 'string') {
|
|
68
|
+
return style;
|
|
69
|
+
}
|
|
70
|
+
if (style && typeof style === 'object') {
|
|
71
|
+
return Object.entries(style)
|
|
72
|
+
.map(function (_a) {
|
|
73
|
+
var key = _a[0], value = _a[1];
|
|
74
|
+
// Convert camelCase to kebab-case
|
|
75
|
+
var cssKey = key.replace(/[A-Z]/g, function (m) { return "-".concat(m.toLowerCase()); });
|
|
76
|
+
return "".concat(cssKey, ": ").concat(value);
|
|
77
|
+
})
|
|
78
|
+
.join('; ');
|
|
79
|
+
}
|
|
80
|
+
return '';
|
|
81
|
+
};
|
|
82
|
+
var generateHandler = function (props, key) {
|
|
83
|
+
var handler = props[key];
|
|
84
|
+
if (typeof handler === 'function') {
|
|
85
|
+
return handler;
|
|
86
|
+
}
|
|
87
|
+
else if (handler && typeof handler === 'object' && handler.isKT) {
|
|
88
|
+
return function (value) { return (handler.value = value); };
|
|
89
|
+
}
|
|
90
|
+
return $emptyFn;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Normalize path by joining parts and ensuring leading slash
|
|
95
|
+
*/
|
|
96
|
+
var normalizePath = function () {
|
|
97
|
+
var paths = [];
|
|
98
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
99
|
+
paths[_i] = arguments[_i];
|
|
100
|
+
}
|
|
101
|
+
var p = paths
|
|
102
|
+
.map(function (p) { return p.split('/'); })
|
|
103
|
+
.flat()
|
|
104
|
+
.filter(Boolean);
|
|
105
|
+
return '/' + p.join('/');
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Parse query string into object
|
|
109
|
+
*/
|
|
110
|
+
var parseQuery = function (queryString) {
|
|
111
|
+
var query = {};
|
|
112
|
+
if (!queryString || queryString === '?') {
|
|
113
|
+
return query;
|
|
114
|
+
}
|
|
115
|
+
var params = queryString.replace(/^\?/, '').split('&');
|
|
116
|
+
for (var _i = 0, params_1 = params; _i < params_1.length; _i++) {
|
|
117
|
+
var param = params_1[_i];
|
|
118
|
+
var _a = param.split('='), key = _a[0], value = _a[1];
|
|
119
|
+
if (key) {
|
|
120
|
+
query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return query;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Build query string from object
|
|
127
|
+
*/
|
|
128
|
+
var buildQuery = function (query) {
|
|
129
|
+
var keys = Object.keys(query);
|
|
130
|
+
if (keys.length === 0)
|
|
131
|
+
return '';
|
|
132
|
+
var params = keys.map(function (key) { return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(query[key])); }).join('&');
|
|
133
|
+
return "?".concat(params);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Substitute params into path pattern
|
|
137
|
+
* @example '/user/:id' + {id: '123'} => '/user/123'
|
|
138
|
+
*/
|
|
139
|
+
var emplaceParams = function (path, params) {
|
|
140
|
+
var result = path;
|
|
141
|
+
for (var key in params) {
|
|
142
|
+
result = result.replace(":".concat(key), params[key]);
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Extract dynamic params from path using pattern
|
|
148
|
+
* @example pattern: '/user/:id', path: '/user/123' => {id: '123'}
|
|
149
|
+
*/
|
|
150
|
+
var extractParams = function (pattern, path) {
|
|
151
|
+
var params = {};
|
|
152
|
+
var patternParts = pattern.split('/');
|
|
153
|
+
var pathParts = path.split('/');
|
|
154
|
+
if (patternParts.length !== pathParts.length) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
for (var i = 0; i < patternParts.length; i++) {
|
|
158
|
+
var patternPart = patternParts[i];
|
|
159
|
+
var pathPart = pathParts[i];
|
|
160
|
+
if (patternPart.startsWith(':')) {
|
|
161
|
+
var paramName = patternPart.slice(1);
|
|
162
|
+
params[paramName] = pathPart;
|
|
163
|
+
}
|
|
164
|
+
else if (patternPart !== pathPart) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return params;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Shared utilities and cached native methods for kt.js framework
|
|
172
|
+
// Re-export all utilities
|
|
173
|
+
Object.defineProperty(window, '@ktjs/shared', { value: '0.19.0' });
|
|
174
|
+
|
|
175
|
+
exports.$append = $append;
|
|
176
|
+
exports.$appendChild = $appendChild;
|
|
177
|
+
exports.$defines = $defines;
|
|
178
|
+
exports.$emptyFn = $emptyFn;
|
|
179
|
+
exports.$entries = $entries;
|
|
180
|
+
exports.$hasOwn = $hasOwn;
|
|
181
|
+
exports.$isArray = $isArray;
|
|
182
|
+
exports.$isThenable = $isThenable;
|
|
183
|
+
exports.$keys = $keys;
|
|
184
|
+
exports.$throw = $throw;
|
|
185
|
+
exports.buildQuery = buildQuery;
|
|
186
|
+
exports.emplaceParams = emplaceParams;
|
|
187
|
+
exports.extractParams = extractParams;
|
|
188
|
+
exports.generateHandler = generateHandler;
|
|
189
|
+
exports.normalizePath = normalizePath;
|
|
190
|
+
exports.parseQuery = parseQuery;
|
|
191
|
+
exports.parseStyle = parseStyle;
|
|
192
|
+
|
|
193
|
+
return exports;
|
|
194
|
+
|
|
195
|
+
})({});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Cached native methods for performance optimization
|
|
2
|
+
const $isArray = Array.isArray;
|
|
3
|
+
const $hasOwn = Object.prototype.hasOwnProperty;
|
|
4
|
+
const $keys = Object.keys;
|
|
5
|
+
const $defines = Object.defineProperties;
|
|
6
|
+
const $entries = Object.entries;
|
|
7
|
+
const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
|
|
8
|
+
|
|
9
|
+
// Error handling utilities
|
|
10
|
+
const $throw = (message) => {
|
|
11
|
+
throw new Error('@ktjs/shared: ' + message);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// String manipulation utilities
|
|
15
|
+
/**
|
|
16
|
+
* Default empty function
|
|
17
|
+
*/
|
|
18
|
+
const $emptyFn = (() => true);
|
|
19
|
+
|
|
20
|
+
// DOM manipulation utilities
|
|
21
|
+
/**
|
|
22
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
23
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
24
|
+
*/
|
|
25
|
+
const $appendChild = HTMLElement.prototype.appendChild;
|
|
26
|
+
const originAppend = HTMLElement.prototype.append;
|
|
27
|
+
const $append = // for ie 9/10/11
|
|
28
|
+
typeof originAppend === 'function'
|
|
29
|
+
? originAppend
|
|
30
|
+
: function (...nodes) {
|
|
31
|
+
if (nodes.length < 50) {
|
|
32
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
33
|
+
const node = nodes[i];
|
|
34
|
+
if (typeof node === 'string') {
|
|
35
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
$appendChild.call(this, node);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const fragment = document.createDocumentFragment();
|
|
44
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
45
|
+
const node = nodes[i];
|
|
46
|
+
if (typeof node === 'string') {
|
|
47
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
$appendChild.call(fragment, node);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
$appendChild.call(this, fragment);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
// Style parsing utilities
|
|
57
|
+
const parseStyle = (style) => {
|
|
58
|
+
if (typeof style === 'string') {
|
|
59
|
+
return style;
|
|
60
|
+
}
|
|
61
|
+
if (style && typeof style === 'object') {
|
|
62
|
+
return Object.entries(style)
|
|
63
|
+
.map(([key, value]) => {
|
|
64
|
+
// Convert camelCase to kebab-case
|
|
65
|
+
const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
66
|
+
return `${cssKey}: ${value}`;
|
|
67
|
+
})
|
|
68
|
+
.join('; ');
|
|
69
|
+
}
|
|
70
|
+
return '';
|
|
71
|
+
};
|
|
72
|
+
const generateHandler = (props, key) => {
|
|
73
|
+
const handler = props[key];
|
|
74
|
+
if (typeof handler === 'function') {
|
|
75
|
+
return handler;
|
|
76
|
+
}
|
|
77
|
+
else if (handler && typeof handler === 'object' && handler.isKT) {
|
|
78
|
+
return (value) => (handler.value = value);
|
|
79
|
+
}
|
|
80
|
+
return $emptyFn;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Normalize path by joining parts and ensuring leading slash
|
|
85
|
+
*/
|
|
86
|
+
const normalizePath = (...paths) => {
|
|
87
|
+
const p = paths
|
|
88
|
+
.map((p) => p.split('/'))
|
|
89
|
+
.flat()
|
|
90
|
+
.filter(Boolean);
|
|
91
|
+
return '/' + p.join('/');
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Parse query string into object
|
|
95
|
+
*/
|
|
96
|
+
const parseQuery = (queryString) => {
|
|
97
|
+
const query = {};
|
|
98
|
+
if (!queryString || queryString === '?') {
|
|
99
|
+
return query;
|
|
100
|
+
}
|
|
101
|
+
const params = queryString.replace(/^\?/, '').split('&');
|
|
102
|
+
for (const param of params) {
|
|
103
|
+
const [key, value] = param.split('=');
|
|
104
|
+
if (key) {
|
|
105
|
+
query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return query;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Build query string from object
|
|
112
|
+
*/
|
|
113
|
+
const buildQuery = (query) => {
|
|
114
|
+
const keys = Object.keys(query);
|
|
115
|
+
if (keys.length === 0)
|
|
116
|
+
return '';
|
|
117
|
+
const params = keys.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`).join('&');
|
|
118
|
+
return `?${params}`;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Substitute params into path pattern
|
|
122
|
+
* @example '/user/:id' + {id: '123'} => '/user/123'
|
|
123
|
+
*/
|
|
124
|
+
const emplaceParams = (path, params) => {
|
|
125
|
+
let result = path;
|
|
126
|
+
for (const key in params) {
|
|
127
|
+
result = result.replace(`:${key}`, params[key]);
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Extract dynamic params from path using pattern
|
|
133
|
+
* @example pattern: '/user/:id', path: '/user/123' => {id: '123'}
|
|
134
|
+
*/
|
|
135
|
+
const extractParams = (pattern, path) => {
|
|
136
|
+
const params = {};
|
|
137
|
+
const patternParts = pattern.split('/');
|
|
138
|
+
const pathParts = path.split('/');
|
|
139
|
+
if (patternParts.length !== pathParts.length) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
143
|
+
const patternPart = patternParts[i];
|
|
144
|
+
const pathPart = pathParts[i];
|
|
145
|
+
if (patternPart.startsWith(':')) {
|
|
146
|
+
const paramName = patternPart.slice(1);
|
|
147
|
+
params[paramName] = pathPart;
|
|
148
|
+
}
|
|
149
|
+
else if (patternPart !== pathPart) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return params;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Shared utilities and cached native methods for kt.js framework
|
|
157
|
+
// Re-export all utilities
|
|
158
|
+
Object.defineProperty(window, '@ktjs/shared', { value: '0.19.0' });
|
|
159
|
+
|
|
160
|
+
export { $append, $appendChild, $defines, $emptyFn, $entries, $hasOwn, $isArray, $isThenable, $keys, $throw, buildQuery, emplaceParams, extractParams, generateHandler, normalizePath, parseQuery, parseStyle };
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ktjs/shared",
|
|
3
|
+
"version": "0.19.0",
|
|
4
|
+
"description": "Shared utilities and cached native methods for kt.js framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"utilities",
|
|
20
|
+
"shared",
|
|
21
|
+
"framework",
|
|
22
|
+
"web",
|
|
23
|
+
"tools"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": {
|
|
27
|
+
"name": "Kasukabe Tsumugi",
|
|
28
|
+
"email": "futami16237@gmail.com"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/baendlorel/kt.js",
|
|
33
|
+
"directory": "packages/shared"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "rollup -c rollup.config.mjs",
|
|
37
|
+
"dev": "rollup -c rollup.config.mjs -w"
|
|
38
|
+
}
|
|
39
|
+
}
|