@ceale/util 1.4.0 → 1.6.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/README.md CHANGED
@@ -1,9 +1,3 @@
1
1
  # @ceale/util
2
2
 
3
- To install dependencies:
4
-
5
- ```bash
6
- npm install
7
- # or
8
- bun install
9
- ```
3
+ 小工具集
package/dist/cjs/index.js CHANGED
@@ -29,40 +29,174 @@ var __export = (target, all) => {
29
29
  // src/index.ts
30
30
  var exports_src = {};
31
31
  __export(exports_src, {
32
- UrlUtil: () => UrlUtil,
33
- StringUtil: () => StringUtil
32
+ uri: () => uri,
33
+ css: () => css
34
34
  });
35
35
  module.exports = __toCommonJS(exports_src);
36
36
 
37
37
  // src/string.ts
38
- var StringUtil = (str) => ({
39
- string: str,
40
- toString: () => str,
41
- valueOf: () => str,
42
- removeStart: (searchString) => str.startsWith(searchString) ? str.slice(searchString.length) : str,
43
- removeEnd: (searchString) => str.endsWith(searchString) ? str.slice(0, -searchString.length) : str,
44
- removeStartAll(searchString) {
45
- while (str.startsWith(searchString)) {
46
- str = str.slice(searchString.length);
38
+ Object.defineProperty(String.prototype, "removePrefix", {
39
+ value: function(prefix) {
40
+ return this.startsWith(prefix) ? this.slice(prefix.length) : this;
41
+ },
42
+ writable: true,
43
+ configurable: true,
44
+ enumerable: false
45
+ });
46
+ Object.defineProperty(String.prototype, "removeSuffix", {
47
+ value: function(suffix) {
48
+ return this.endsWith(suffix) ? this.slice(0, -suffix.length) : this;
49
+ },
50
+ writable: true,
51
+ configurable: true,
52
+ enumerable: false
53
+ });
54
+ Object.defineProperty(String.prototype, "removeAllPrefixes", {
55
+ value: function(prefix) {
56
+ if (prefix.length === 0)
57
+ return this;
58
+ let str = this;
59
+ while (str.startsWith(prefix)) {
60
+ str = str.slice(prefix.length);
47
61
  }
48
62
  return str;
49
63
  },
50
- removeEndAll(searchString) {
51
- while (str.endsWith(searchString)) {
52
- str = str.slice(0, -searchString.length);
64
+ writable: true,
65
+ configurable: true,
66
+ enumerable: false
67
+ });
68
+ Object.defineProperty(String.prototype, "removeAllSuffixes", {
69
+ value: function(suffix) {
70
+ if (suffix.length === 0)
71
+ return this;
72
+ let str = this;
73
+ while (str.endsWith(suffix)) {
74
+ str = str.slice(0, -suffix.length);
53
75
  }
54
76
  return str;
55
- }
77
+ },
78
+ writable: true,
79
+ configurable: true,
80
+ enumerable: false
81
+ });
82
+ Object.defineProperty(String.prototype, "toCamelCase", {
83
+ value: function() {
84
+ return this.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
85
+ },
86
+ writable: true,
87
+ configurable: true,
88
+ enumerable: false
56
89
  });
57
- // src/url.ts
58
- var UrlUtil;
59
- ((UrlUtil) => {
60
- UrlUtil.join = (...path) => {
61
- return path.filter((p) => p !== "").map((p, index) => {
90
+ Object.defineProperty(String.prototype, "toKebabCase", {
91
+ value: function() {
92
+ return this.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
93
+ },
94
+ writable: true,
95
+ configurable: true,
96
+ enumerable: false
97
+ });
98
+ // src/uri.ts
99
+ var uri;
100
+ ((uri) => {
101
+ const leftSlash = /^\/(?=[^\/])/g;
102
+ const rightSlash = /(?<=[^\/])\/$/g;
103
+ const innerSlash = /(?<=[^\/])\/(?=[^\/])/g;
104
+ uri.join = (...path) => {
105
+ return path.filter((path2) => path2.length > 0).map((path2, index, pathArray) => {
62
106
  if (index === 0) {
63
- return StringUtil(p).removeEnd("/");
107
+ return path2.replace(rightSlash, "").split(innerSlash);
108
+ } else if (index === pathArray.length - 1) {
109
+ return path2.replace(leftSlash, "").split(innerSlash);
110
+ } else {
111
+ return path2.replace(leftSlash, "").replace(rightSlash, "").split(innerSlash);
112
+ }
113
+ }).flat().reduce((stack, path2) => {
114
+ if (path2 === "." || path2 === "/." || path2 === "./") {
115
+ return stack;
116
+ } else if (path2 === ".." || path2 === "/.." || path2 === "../") {
117
+ stack.pop();
118
+ return stack;
119
+ } else {
120
+ stack.push(path2);
121
+ return stack;
122
+ }
123
+ }, []).reduce((path2, segment) => {
124
+ if (path2.length === 0) {
125
+ return path2 + segment;
126
+ } else if (path2.endsWith("/") || segment.startsWith("/")) {
127
+ return path2 + segment;
128
+ } else {
129
+ return path2 + "/" + segment;
64
130
  }
65
- return "/" + StringUtil(p).removeStart("/");
66
- }).join("");
131
+ }, "");
132
+ };
133
+ })(uri ||= {});
134
+ // src/class.ts
135
+ Object.defineProperty(Function.prototype, "isDirectSubclass", {
136
+ value: function(potentialChild) {
137
+ if (typeof potentialChild !== "function" || typeof this !== "function") {
138
+ return false;
139
+ }
140
+ return Object.getPrototypeOf(potentialChild) === this;
141
+ },
142
+ writable: true,
143
+ configurable: true,
144
+ enumerable: false
145
+ });
146
+ Object.defineProperty(Function.prototype, "isSubclass", {
147
+ value: function(potentialDescendant) {
148
+ if (typeof potentialDescendant !== "function" || typeof this !== "function") {
149
+ return false;
150
+ }
151
+ let current = potentialDescendant;
152
+ while (typeof current === "function") {
153
+ if (current === this) {
154
+ return true;
155
+ }
156
+ current = Object.getPrototypeOf(current);
157
+ if (current === Function.prototype)
158
+ break;
159
+ }
160
+ return false;
161
+ },
162
+ writable: true,
163
+ configurable: true,
164
+ enumerable: false
165
+ });
166
+ Object.defineProperty(Function.prototype, "isDirectInstance", {
167
+ value: function(potentialInstance) {
168
+ if (typeof this !== "function" || potentialInstance === null || typeof potentialInstance !== "object") {
169
+ return false;
170
+ }
171
+ return Object.getPrototypeOf(potentialInstance).constructor === this;
172
+ },
173
+ writable: true,
174
+ configurable: true,
175
+ enumerable: false
176
+ });
177
+ Object.defineProperty(Function.prototype, "isInstance", {
178
+ value: function(potentialInstance) {
179
+ return typeof this === "function" && potentialInstance instanceof this;
180
+ },
181
+ writable: true,
182
+ configurable: true,
183
+ enumerable: false
184
+ });
185
+ // src/css.ts
186
+ var css;
187
+ ((css) => {
188
+ css.rule = (rule2) => {
189
+ return Object.entries(rule2).map(([key, value]) => `${key.toKebabCase()}: ${value};`).join(`
190
+ `);
191
+ };
192
+ css.selector = (selector2, rule2) => {
193
+ return selector2 + "{" + rule2 + "}";
194
+ };
195
+ css.at = (identifier, rule2) => {
196
+ return identifier + (rule2 ? "{" + rule2 + "}" : "");
197
+ };
198
+ css.join = (...rules) => {
199
+ return rules.join(`
200
+ `);
67
201
  };
68
- })(UrlUtil ||= {});
202
+ })(css ||= {});
package/dist/esm/index.js CHANGED
@@ -1,36 +1,170 @@
1
1
  // src/string.ts
2
- var StringUtil = (str) => ({
3
- string: str,
4
- toString: () => str,
5
- valueOf: () => str,
6
- removeStart: (searchString) => str.startsWith(searchString) ? str.slice(searchString.length) : str,
7
- removeEnd: (searchString) => str.endsWith(searchString) ? str.slice(0, -searchString.length) : str,
8
- removeStartAll(searchString) {
9
- while (str.startsWith(searchString)) {
10
- str = str.slice(searchString.length);
2
+ Object.defineProperty(String.prototype, "removePrefix", {
3
+ value: function(prefix) {
4
+ return this.startsWith(prefix) ? this.slice(prefix.length) : this;
5
+ },
6
+ writable: true,
7
+ configurable: true,
8
+ enumerable: false
9
+ });
10
+ Object.defineProperty(String.prototype, "removeSuffix", {
11
+ value: function(suffix) {
12
+ return this.endsWith(suffix) ? this.slice(0, -suffix.length) : this;
13
+ },
14
+ writable: true,
15
+ configurable: true,
16
+ enumerable: false
17
+ });
18
+ Object.defineProperty(String.prototype, "removeAllPrefixes", {
19
+ value: function(prefix) {
20
+ if (prefix.length === 0)
21
+ return this;
22
+ let str = this;
23
+ while (str.startsWith(prefix)) {
24
+ str = str.slice(prefix.length);
11
25
  }
12
26
  return str;
13
27
  },
14
- removeEndAll(searchString) {
15
- while (str.endsWith(searchString)) {
16
- str = str.slice(0, -searchString.length);
28
+ writable: true,
29
+ configurable: true,
30
+ enumerable: false
31
+ });
32
+ Object.defineProperty(String.prototype, "removeAllSuffixes", {
33
+ value: function(suffix) {
34
+ if (suffix.length === 0)
35
+ return this;
36
+ let str = this;
37
+ while (str.endsWith(suffix)) {
38
+ str = str.slice(0, -suffix.length);
17
39
  }
18
40
  return str;
19
- }
41
+ },
42
+ writable: true,
43
+ configurable: true,
44
+ enumerable: false
45
+ });
46
+ Object.defineProperty(String.prototype, "toCamelCase", {
47
+ value: function() {
48
+ return this.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
49
+ },
50
+ writable: true,
51
+ configurable: true,
52
+ enumerable: false
20
53
  });
21
- // src/url.ts
22
- var UrlUtil;
23
- ((UrlUtil) => {
24
- UrlUtil.join = (...path) => {
25
- return path.filter((p) => p !== "").map((p, index) => {
54
+ Object.defineProperty(String.prototype, "toKebabCase", {
55
+ value: function() {
56
+ return this.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
57
+ },
58
+ writable: true,
59
+ configurable: true,
60
+ enumerable: false
61
+ });
62
+ // src/uri.ts
63
+ var uri;
64
+ ((uri) => {
65
+ const leftSlash = /^\/(?=[^\/])/g;
66
+ const rightSlash = /(?<=[^\/])\/$/g;
67
+ const innerSlash = /(?<=[^\/])\/(?=[^\/])/g;
68
+ uri.join = (...path) => {
69
+ return path.filter((path2) => path2.length > 0).map((path2, index, pathArray) => {
26
70
  if (index === 0) {
27
- return StringUtil(p).removeEnd("/");
71
+ return path2.replace(rightSlash, "").split(innerSlash);
72
+ } else if (index === pathArray.length - 1) {
73
+ return path2.replace(leftSlash, "").split(innerSlash);
74
+ } else {
75
+ return path2.replace(leftSlash, "").replace(rightSlash, "").split(innerSlash);
76
+ }
77
+ }).flat().reduce((stack, path2) => {
78
+ if (path2 === "." || path2 === "/." || path2 === "./") {
79
+ return stack;
80
+ } else if (path2 === ".." || path2 === "/.." || path2 === "../") {
81
+ stack.pop();
82
+ return stack;
83
+ } else {
84
+ stack.push(path2);
85
+ return stack;
86
+ }
87
+ }, []).reduce((path2, segment) => {
88
+ if (path2.length === 0) {
89
+ return path2 + segment;
90
+ } else if (path2.endsWith("/") || segment.startsWith("/")) {
91
+ return path2 + segment;
92
+ } else {
93
+ return path2 + "/" + segment;
28
94
  }
29
- return "/" + StringUtil(p).removeStart("/");
30
- }).join("");
95
+ }, "");
96
+ };
97
+ })(uri ||= {});
98
+ // src/class.ts
99
+ Object.defineProperty(Function.prototype, "isDirectSubclass", {
100
+ value: function(potentialChild) {
101
+ if (typeof potentialChild !== "function" || typeof this !== "function") {
102
+ return false;
103
+ }
104
+ return Object.getPrototypeOf(potentialChild) === this;
105
+ },
106
+ writable: true,
107
+ configurable: true,
108
+ enumerable: false
109
+ });
110
+ Object.defineProperty(Function.prototype, "isSubclass", {
111
+ value: function(potentialDescendant) {
112
+ if (typeof potentialDescendant !== "function" || typeof this !== "function") {
113
+ return false;
114
+ }
115
+ let current = potentialDescendant;
116
+ while (typeof current === "function") {
117
+ if (current === this) {
118
+ return true;
119
+ }
120
+ current = Object.getPrototypeOf(current);
121
+ if (current === Function.prototype)
122
+ break;
123
+ }
124
+ return false;
125
+ },
126
+ writable: true,
127
+ configurable: true,
128
+ enumerable: false
129
+ });
130
+ Object.defineProperty(Function.prototype, "isDirectInstance", {
131
+ value: function(potentialInstance) {
132
+ if (typeof this !== "function" || potentialInstance === null || typeof potentialInstance !== "object") {
133
+ return false;
134
+ }
135
+ return Object.getPrototypeOf(potentialInstance).constructor === this;
136
+ },
137
+ writable: true,
138
+ configurable: true,
139
+ enumerable: false
140
+ });
141
+ Object.defineProperty(Function.prototype, "isInstance", {
142
+ value: function(potentialInstance) {
143
+ return typeof this === "function" && potentialInstance instanceof this;
144
+ },
145
+ writable: true,
146
+ configurable: true,
147
+ enumerable: false
148
+ });
149
+ // src/css.ts
150
+ var css;
151
+ ((css) => {
152
+ css.rule = (rule2) => {
153
+ return Object.entries(rule2).map(([key, value]) => `${key.toKebabCase()}: ${value};`).join(`
154
+ `);
155
+ };
156
+ css.selector = (selector2, rule2) => {
157
+ return selector2 + "{" + rule2 + "}";
158
+ };
159
+ css.at = (identifier, rule2) => {
160
+ return identifier + (rule2 ? "{" + rule2 + "}" : "");
161
+ };
162
+ css.join = (...rules) => {
163
+ return rules.join(`
164
+ `);
31
165
  };
32
- })(UrlUtil ||= {});
166
+ })(css ||= {});
33
167
  export {
34
- UrlUtil,
35
- StringUtil
168
+ uri,
169
+ css
36
170
  };
@@ -0,0 +1,32 @@
1
+ type AnyClass = new (...args: any[]) => any;
2
+ declare global {
3
+ interface Function {
4
+ /**
5
+ * 检查 `potentialChild` 是否是当前类的直接子类
6
+ * @param potentialChild 潜在的子类构造函数
7
+ * @returns 如果是直接子类,则返回 `true`;否则返回 `false`
8
+ */
9
+ isDirectSubclass(this: AnyClass, potentialChild: unknown): boolean;
10
+ /**
11
+ * 检查 `potentialDescendant` 是否是当前类的子孙类或当前类本身
12
+ * @param potentialDescendant 潜在的子孙类或类本身
13
+ * @returns 如果是子孙类或类本身,则返回 `true`;否则返回 `false`
14
+ */
15
+ isSubclass(this: AnyClass, potentialDescendant: unknown): boolean;
16
+ /**
17
+ * 检查 `potentialInstance` 是否由当前类直接构造
18
+ * 判断依据: `Object.getPrototypeOf(potentialInstance).constructor === this`
19
+ * @param potentialInstance 潜在的实例对象
20
+ * @returns 如果是由当前类直接创建的实例,则返回 `true`;否则返回 `false`
21
+ */
22
+ isDirectInstance(this: AnyClass, potentialInstance: unknown): boolean;
23
+ /**
24
+ * 检查 `potentialInstance` 是否是当前类或其任何子类的实例
25
+ * 内部使用 `instanceof` 操作符
26
+ * @param potentialInstance 潜在的实例对象
27
+ * @returns 如果是实例,则返回 `true`;否则返回 `false`
28
+ */
29
+ isInstance(this: AnyClass, potentialInstance: unknown): boolean;
30
+ }
31
+ }
32
+ export {};
@@ -0,0 +1,77 @@
1
+ import type { CSSProperties } from "vue";
2
+ import type { AtRules } from "csstype";
3
+ export declare namespace css {
4
+ const RuleValueSymbol: unique symbol;
5
+ type RuleValue = string & {
6
+ [RuleValueSymbol]: never;
7
+ };
8
+ const RuleBlockValueSymbol: unique symbol;
9
+ type RuleBlockValue = string & {
10
+ [RuleBlockValueSymbol]: never;
11
+ };
12
+ const AtValueSymbol: unique symbol;
13
+ type AtValue = string & {
14
+ [AtValueSymbol]: never;
15
+ };
16
+ /**
17
+ * 从一个样式对象,创建一个 CSS 规则字符串
18
+ * @param styles 一个样式对象,使用 Vue 的 `CSSProperties` 类型,同时允许自定义属性
19
+ * @returns 返回类型为`RuleValue`的字符串,可以传入`css.selector()`和`css.at()`
20
+ *
21
+ * @example
22
+ * css.rule({
23
+ * backgroundColor: "red",
24
+ * fontSize: "16px",
25
+ * "--my-custom-var": "blue"
26
+ * })
27
+ */
28
+ export const rule: (rule: CSSProperties & {
29
+ [key: string]: string;
30
+ }) => RuleValue;
31
+ /**
32
+ * 根据选择器和 CSS 规则,创建一个 CSS 规则块字符串
33
+ * @param selector CSS 选择器字符串
34
+ * @param rule CSS 规则,类型为`RuleValue`的字符串
35
+ * @returns 返回类型为`RuleBlockValue`的字符串,可以传入`css.at()`和`css.join()`
36
+ *
37
+ * @example
38
+ * css.selector(
39
+ * "#my-element",
40
+ * css.rule({
41
+ * color: "blue"
42
+ * })
43
+ * ) // -> "#my-element { color: blue; }"
44
+ */
45
+ export const selector: (selector: string, rule: RuleValue) => RuleBlockValue;
46
+ /**
47
+ * 根据 @ 规则和可选的 CSS 规则或规则块,创建一个 @ 规则块字符串
48
+ * @param identifier @ 规则,如 "@media (min-width: 768px)"
49
+ * @param rule 可选,类型为`RuleValue`的字符串,或类型为`SelectorValue`的字符串
50
+ * @returns 返回类型为`AtValue`的字符串,可以传入`css.join()`
51
+ *
52
+ * @example
53
+ * css.at(
54
+ * "@font-face",
55
+ * css.rule({
56
+ * scr: "..."
57
+ * })
58
+ * ) // -> "@font-face { scr: "..."; }"
59
+ *
60
+ * @example
61
+ * css.at(
62
+ * "@media (min-width: 768px)",
63
+ * css.selector(
64
+ * "#my-element",
65
+ * css.rule(...)
66
+ * )
67
+ * ) // -> "@media (min-width: 768px) { #my-element { ... } }"
68
+ */
69
+ export const at: (identifier: AtRules | (string & {}), rule?: RuleValue | RuleBlockValue) => AtValue;
70
+ /**
71
+ * 拼接 CSS 规则块和 @ 规则块,返回一个字符串
72
+ * @param rules CSS 规则块和 @ 规则块,类型为`RuleBlockValue`或`AtValue`的字符串
73
+ * @returns 返回标准的字符串
74
+ */
75
+ export const join: (...rules: (RuleBlockValue | AtValue)[]) => string;
76
+ export {};
77
+ }
@@ -1,2 +1,4 @@
1
1
  export * from "./string";
2
- export * from "./url";
2
+ export * from "./uri";
3
+ export * from "./class";
4
+ export * from "./css";
@@ -1,9 +1,39 @@
1
- export declare const StringUtil: (str: string) => {
2
- string: string;
3
- toString: () => string;
4
- valueOf: () => string;
5
- removeStart: (searchString: string) => string;
6
- removeEnd: (searchString: string) => string;
7
- removeStartAll(searchString: string): string;
8
- removeEndAll(searchString: string): string;
9
- };
1
+ declare global {
2
+ interface String {
3
+ /**
4
+ * 移除字符串的前缀`prefix`,如果不以`prefix`开头,则返回原字符串
5
+ * @param prefix 指定字符串
6
+ * @returns 移除后的字符串
7
+ */
8
+ removePrefix(prefix: string): string;
9
+ /**
10
+ * 移除字符串的后缀`suffix`,如果不以`suffix`结尾,则返回原字符串
11
+ * @param suffix 待匹配的串
12
+ * @returns 移除后的字符串
13
+ */
14
+ removeSuffix(suffix: string): string;
15
+ /**
16
+ * 移除字符串连续出现的若干个前缀`prefix`,如果不以`prefix`开头,则返回原字符串
17
+ * @param prefix 待匹配的串
18
+ * @returns 移除后的字符串
19
+ */
20
+ removeAllPrefixes(prefix: string): string;
21
+ /**
22
+ * 移除字符串连续出现的若干个后缀`suffix`,如果不以`suffix`结尾,则返回原字符串
23
+ * @param suffix 待匹配的串
24
+ * @returns 移除后的字符串
25
+ */
26
+ removeAllSuffixes(suffix: string): string;
27
+ /**
28
+ * 将字符串转为驼峰命名
29
+ * @returns 驼峰命名的字符串
30
+ */
31
+ toCamelCase(): string;
32
+ /**
33
+ * 将字符串转为连字符命名
34
+ * @returns 连字符命名的字符串
35
+ */
36
+ toKebabCase(): string;
37
+ }
38
+ }
39
+ export {};
@@ -0,0 +1,24 @@
1
+ export declare namespace uri {
2
+ /**
3
+ * 拼接路径字符串:
4
+ * - 解析路径中的 `.` 和 `..`
5
+ * - 保留 URL 协议头 (如 `http://`) 和协议自适应的开头 (如 `//domain`)
6
+ * - 保留主动传入的连续斜杠 (如 `a//b`)
7
+ *
8
+ * @param path 若干个要拼接的路径片段
9
+ * @returns 拼接后的路径字符串
10
+ *
11
+ * @example
12
+ * // 基础拼接
13
+ * uri.join('/a/', 'b', '/c') // -> "/a/b/c"
14
+ *
15
+ * @example
16
+ * // 路径解析
17
+ * uri.join('/a/b/../c') // -> "/a/c"
18
+ *
19
+ * @example
20
+ * // 保留协议头
21
+ * uri.join("http://example.com", "a") // -> "http://example.com/a"
22
+ */
23
+ const join: (...path: string[]) => string;
24
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ceale/util",
3
3
  "author": "Ceale",
4
- "version": "1.4.0",
4
+ "version": "1.6.0",
5
5
  "module": "index.ts",
6
6
  "type": "module",
7
7
  "main": "dist/esm/index.js",
@@ -14,7 +14,7 @@
14
14
  "build": "bun run build:esm && bun run build:cjs && bun run build:ts",
15
15
  "build:esm": "bun build --outdir=dist/esm/ --format=esm --target=node src/index.ts",
16
16
  "build:cjs": "bun build --outdir=dist/cjs/ --format=cjs --target=node src/index.ts",
17
- "build:ts": "tsc --outDir dist/ts/"
17
+ "build:ts": "tsc --project tsconfig.build.json"
18
18
  },
19
19
  "exports": {
20
20
  ".": {
@@ -29,5 +29,9 @@
29
29
  },
30
30
  "peerDependencies": {
31
31
  "typescript": "^5"
32
+ },
33
+ "dependencies": {
34
+ "@types/vue": "^2.0.0",
35
+ "csstype": "^3.1.3"
32
36
  }
33
37
  }
@@ -1,3 +0,0 @@
1
- export declare namespace UrlUtil {
2
- const join: (...path: string[]) => string;
3
- }