@planet-matrix/mobius-model 0.5.0 → 0.9.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/CHANGELOG.md +61 -0
- package/README.md +123 -36
- package/dist/index.js +715 -4
- package/dist/index.js.map +981 -13
- package/oxlint.config.ts +6 -0
- package/package.json +36 -18
- package/src/abort/README.md +92 -0
- package/src/abort/abort-manager.ts +278 -0
- package/src/abort/abort-signal-listener-manager.ts +81 -0
- package/src/abort/index.ts +2 -0
- package/src/ai/README.md +1 -0
- package/src/ai/ai.ts +107 -0
- package/src/ai/chat-completion-ai/aihubmix-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/chat-completion-ai.ts +270 -0
- package/src/ai/chat-completion-ai/chat-completion.ts +189 -0
- package/src/ai/chat-completion-ai/index.ts +7 -0
- package/src/ai/chat-completion-ai/lingyiwanwu-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/ohmygpt-chat-completion.ts +78 -0
- package/src/ai/chat-completion-ai/openai-next-chat-completion.ts +78 -0
- package/src/ai/embedding-ai/embedding-ai.ts +63 -0
- package/src/ai/embedding-ai/embedding.ts +50 -0
- package/src/ai/embedding-ai/index.ts +4 -0
- package/src/ai/embedding-ai/openai-next-embedding.ts +23 -0
- package/src/ai/index.ts +4 -0
- package/src/aio/README.md +100 -0
- package/src/aio/content.ts +141 -0
- package/src/aio/index.ts +3 -0
- package/src/aio/json.ts +127 -0
- package/src/aio/prompt.ts +246 -0
- package/src/basic/README.md +72 -116
- package/src/basic/error.ts +19 -5
- package/src/basic/function.ts +83 -64
- package/src/basic/index.ts +1 -0
- package/src/basic/is.ts +152 -71
- package/src/basic/promise.ts +29 -8
- package/src/basic/schedule.ts +111 -0
- package/src/basic/stream.ts +135 -25
- package/src/basic/string.ts +2 -33
- package/src/color/README.md +105 -0
- package/src/color/index.ts +3 -0
- package/src/color/internal.ts +42 -0
- package/src/color/rgb/analyze.ts +236 -0
- package/src/color/rgb/construct.ts +130 -0
- package/src/color/rgb/convert.ts +227 -0
- package/src/color/rgb/derive.ts +303 -0
- package/src/color/rgb/index.ts +6 -0
- package/src/color/rgb/internal.ts +208 -0
- package/src/color/rgb/parse.ts +302 -0
- package/src/color/rgb/serialize.ts +144 -0
- package/src/color/types.ts +57 -0
- package/src/color/xyz/analyze.ts +80 -0
- package/src/color/xyz/construct.ts +19 -0
- package/src/color/xyz/convert.ts +71 -0
- package/src/color/xyz/index.ts +3 -0
- package/src/color/xyz/internal.ts +23 -0
- package/src/credential/README.md +107 -0
- package/src/credential/api-key.ts +158 -0
- package/src/credential/bearer.ts +73 -0
- package/src/credential/index.ts +4 -0
- package/src/credential/json-web-token.ts +96 -0
- package/src/credential/password.ts +170 -0
- package/src/cron/README.md +86 -0
- package/src/cron/cron.ts +87 -0
- package/src/cron/index.ts +1 -0
- package/src/css/README.md +93 -0
- package/src/css/class.ts +559 -0
- package/src/css/index.ts +1 -0
- package/src/drizzle/README.md +1 -0
- package/src/drizzle/drizzle.ts +1 -0
- package/src/drizzle/helper.ts +47 -0
- package/src/drizzle/index.ts +5 -0
- package/src/drizzle/infer.ts +52 -0
- package/src/drizzle/kysely.ts +8 -0
- package/src/drizzle/pagination.ts +200 -0
- package/src/email/README.md +1 -0
- package/src/email/index.ts +1 -0
- package/src/email/resend.ts +25 -0
- package/src/encoding/README.md +66 -79
- package/src/encoding/base64.ts +13 -4
- package/src/environment/README.md +97 -0
- package/src/environment/basic.ts +26 -0
- package/src/environment/device.ts +311 -0
- package/src/environment/feature.ts +285 -0
- package/src/environment/geo.ts +337 -0
- package/src/environment/index.ts +7 -0
- package/src/environment/runtime.ts +400 -0
- package/src/environment/snapshot.ts +60 -0
- package/src/environment/variable.ts +239 -0
- package/src/event/README.md +90 -0
- package/src/event/class-event-proxy.ts +229 -0
- package/src/event/common.ts +29 -0
- package/src/event/event-manager.ts +203 -0
- package/src/event/index.ts +4 -0
- package/src/event/instance-event-proxy.ts +187 -0
- package/src/event/internal.ts +24 -0
- package/src/exception/README.md +96 -0
- package/src/exception/browser.ts +219 -0
- package/src/exception/index.ts +4 -0
- package/src/exception/nodejs.ts +169 -0
- package/src/exception/normalize.ts +106 -0
- package/src/exception/types.ts +99 -0
- package/src/form/README.md +25 -0
- package/src/form/index.ts +1 -0
- package/src/form/inputor-controller/base.ts +874 -0
- package/src/form/inputor-controller/boolean.ts +39 -0
- package/src/form/inputor-controller/file.ts +39 -0
- package/src/form/inputor-controller/form.ts +181 -0
- package/src/form/inputor-controller/helper.ts +117 -0
- package/src/form/inputor-controller/index.ts +17 -0
- package/src/form/inputor-controller/multi-select.ts +99 -0
- package/src/form/inputor-controller/number.ts +116 -0
- package/src/form/inputor-controller/select.ts +109 -0
- package/src/form/inputor-controller/text.ts +82 -0
- package/src/http/READMD.md +1 -0
- package/src/http/api/api-core.ts +84 -0
- package/src/http/api/api-handler.ts +79 -0
- package/src/http/api/api-host.ts +47 -0
- package/src/http/api/api-result.ts +56 -0
- package/src/http/api/api-schema.ts +154 -0
- package/src/http/api/api-server.ts +130 -0
- package/src/http/api/api-test.ts +142 -0
- package/src/http/api/api-type.ts +37 -0
- package/src/http/api/api.ts +81 -0
- package/src/http/api/index.ts +11 -0
- package/src/http/api-adapter/api-core-node-http.ts +260 -0
- package/src/http/api-adapter/api-host-node-http.ts +156 -0
- package/src/http/api-adapter/api-result-arktype.ts +297 -0
- package/src/http/api-adapter/api-result-zod.ts +286 -0
- package/src/http/api-adapter/index.ts +5 -0
- package/src/http/bin/gen-api-list/gen-api-list.ts +126 -0
- package/src/http/bin/gen-api-list/index.ts +1 -0
- package/src/http/bin/gen-api-test/gen-api-test.ts +136 -0
- package/src/http/bin/gen-api-test/index.ts +1 -0
- package/src/http/bin/gen-api-type/calc-code.ts +25 -0
- package/src/http/bin/gen-api-type/gen-api-type.ts +127 -0
- package/src/http/bin/gen-api-type/index.ts +2 -0
- package/src/http/bin/index.ts +2 -0
- package/src/http/index.ts +3 -0
- package/src/huawei/README.md +1 -0
- package/src/huawei/index.ts +2 -0
- package/src/huawei/moderation/index.ts +1 -0
- package/src/huawei/moderation/moderation.ts +355 -0
- package/src/huawei/obs/esdk-obs-nodejs.d.ts +87 -0
- package/src/huawei/obs/index.ts +1 -0
- package/src/huawei/obs/obs.ts +42 -0
- package/src/identifier/README.md +92 -0
- package/src/identifier/id.ts +119 -0
- package/src/identifier/index.ts +2 -0
- package/src/identifier/uuid.ts +187 -0
- package/src/index.ts +33 -1
- package/src/json/README.md +92 -0
- package/src/json/index.ts +1 -0
- package/src/json/repair.ts +18 -0
- package/src/log/README.md +79 -0
- package/src/log/index.ts +5 -0
- package/src/log/log-emitter.ts +72 -0
- package/src/log/log-record.ts +10 -0
- package/src/log/log-scheduler.ts +74 -0
- package/src/log/log-type.ts +8 -0
- package/src/log/logger.ts +554 -0
- package/src/openai/README.md +1 -0
- package/src/openai/index.ts +1 -0
- package/src/openai/openai.ts +510 -0
- package/src/orchestration/README.md +91 -0
- package/src/orchestration/coordination/barrier.ts +214 -0
- package/src/orchestration/coordination/count-down-latch.ts +215 -0
- package/src/orchestration/coordination/errors.ts +98 -0
- package/src/orchestration/coordination/index.ts +16 -0
- package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
- package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
- package/src/orchestration/coordination/keyed-lock.ts +168 -0
- package/src/orchestration/coordination/mutex.ts +257 -0
- package/src/orchestration/coordination/permit.ts +127 -0
- package/src/orchestration/coordination/read-write-lock.ts +444 -0
- package/src/orchestration/coordination/semaphore.ts +280 -0
- package/src/orchestration/dispatching/dispatcher.ts +83 -0
- package/src/orchestration/dispatching/index.ts +2 -0
- package/src/orchestration/dispatching/selector/base-selector.ts +39 -0
- package/src/orchestration/dispatching/selector/down-count-selector.ts +119 -0
- package/src/orchestration/dispatching/selector/index.ts +2 -0
- package/src/orchestration/index.ts +3 -0
- package/src/orchestration/scheduling/index.ts +2 -0
- package/src/orchestration/scheduling/scheduler.ts +103 -0
- package/src/orchestration/scheduling/task.ts +32 -0
- package/src/random/README.md +56 -86
- package/src/random/base.ts +66 -0
- package/src/random/index.ts +5 -1
- package/src/random/random-boolean.ts +40 -0
- package/src/random/random-integer.ts +60 -0
- package/src/random/random-number.ts +72 -0
- package/src/random/random-string.ts +66 -0
- package/src/reactor/README.md +4 -0
- package/src/reactor/reactor-core/primitive.ts +9 -9
- package/src/reactor/reactor-core/reactive-system.ts +5 -5
- package/src/request/README.md +108 -0
- package/src/request/fetch/base.ts +108 -0
- package/src/request/fetch/browser.ts +285 -0
- package/src/request/fetch/general.ts +20 -0
- package/src/request/fetch/index.ts +4 -0
- package/src/request/fetch/nodejs.ts +285 -0
- package/src/request/index.ts +2 -0
- package/src/request/request/base.ts +250 -0
- package/src/request/request/general.ts +64 -0
- package/src/request/request/index.ts +3 -0
- package/src/request/request/resource.ts +68 -0
- package/src/result/README.md +4 -0
- package/src/result/controller.ts +54 -0
- package/src/result/either.ts +193 -0
- package/src/result/index.ts +2 -0
- package/src/route/README.md +105 -0
- package/src/route/adapter/browser.ts +122 -0
- package/src/route/adapter/driver.ts +56 -0
- package/src/route/adapter/index.ts +2 -0
- package/src/route/index.ts +3 -0
- package/src/route/router/index.ts +2 -0
- package/src/route/router/route.ts +630 -0
- package/src/route/router/router.ts +1642 -0
- package/src/route/uri/hash.ts +308 -0
- package/src/route/uri/index.ts +7 -0
- package/src/route/uri/pathname.ts +376 -0
- package/src/route/uri/search.ts +413 -0
- package/src/singleton/README.md +79 -0
- package/src/singleton/factory.ts +55 -0
- package/src/singleton/index.ts +2 -0
- package/src/singleton/manager.ts +204 -0
- package/src/socket/README.md +105 -0
- package/src/socket/client/index.ts +2 -0
- package/src/socket/client/socket-unit.ts +660 -0
- package/src/socket/client/socket.ts +203 -0
- package/src/socket/common/index.ts +2 -0
- package/src/socket/common/socket-unit-common.ts +23 -0
- package/src/socket/common/socket-unit-heartbeat.ts +427 -0
- package/src/socket/index.ts +3 -0
- package/src/socket/server/index.ts +3 -0
- package/src/socket/server/server.ts +183 -0
- package/src/socket/server/socket-unit.ts +449 -0
- package/src/socket/server/socket.ts +264 -0
- package/src/storage/README.md +107 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/table.ts +449 -0
- package/src/timer/README.md +86 -0
- package/src/timer/expiration/expiration-manager.ts +594 -0
- package/src/timer/expiration/index.ts +3 -0
- package/src/timer/expiration/min-heap.ts +208 -0
- package/src/timer/expiration/remaining-manager.ts +241 -0
- package/src/timer/index.ts +1 -0
- package/src/tube/README.md +99 -0
- package/src/tube/helper.ts +138 -0
- package/src/tube/index.ts +2 -0
- package/src/tube/tube.ts +880 -0
- package/src/type/README.md +54 -307
- package/src/type/class.ts +2 -2
- package/src/type/index.ts +14 -14
- package/src/type/is.ts +265 -2
- package/src/type/object.ts +37 -0
- package/src/type/string.ts +7 -2
- package/src/type/tuple.ts +6 -6
- package/src/type/union.ts +16 -0
- package/src/web/README.md +77 -0
- package/src/web/capture.ts +35 -0
- package/src/web/clipboard.ts +97 -0
- package/src/web/dom.ts +117 -0
- package/src/web/download.ts +16 -0
- package/src/web/event.ts +46 -0
- package/src/web/index.ts +10 -0
- package/src/web/local-storage.ts +113 -0
- package/src/web/location.ts +28 -0
- package/src/web/permission.ts +172 -0
- package/src/web/script-loader.ts +432 -0
- package/src/weixin/README.md +1 -0
- package/src/weixin/index.ts +2 -0
- package/src/weixin/official-account/authorization.ts +159 -0
- package/src/weixin/official-account/index.ts +2 -0
- package/src/weixin/official-account/js-api.ts +134 -0
- package/src/weixin/open/index.ts +1 -0
- package/src/weixin/open/oauth2.ts +133 -0
- package/tests/unit/abort/abort-manager.spec.ts +225 -0
- package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
- package/tests/unit/ai/ai.spec.ts +85 -0
- package/tests/unit/aio/content.spec.ts +105 -0
- package/tests/unit/aio/json.spec.ts +147 -0
- package/tests/unit/aio/prompt.spec.ts +111 -0
- package/tests/unit/basic/array.spec.ts +1 -1
- package/tests/unit/basic/error.spec.ts +16 -4
- package/tests/unit/basic/schedule.spec.ts +74 -0
- package/tests/unit/basic/stream.spec.ts +91 -38
- package/tests/unit/basic/string.spec.ts +0 -9
- package/tests/unit/color/rgb/analyze.spec.ts +110 -0
- package/tests/unit/color/rgb/construct.spec.ts +56 -0
- package/tests/unit/color/rgb/convert.spec.ts +60 -0
- package/tests/unit/color/rgb/derive.spec.ts +103 -0
- package/tests/unit/color/rgb/parse.spec.ts +66 -0
- package/tests/unit/color/rgb/serialize.spec.ts +46 -0
- package/tests/unit/color/xyz/analyze.spec.ts +33 -0
- package/tests/unit/color/xyz/construct.spec.ts +10 -0
- package/tests/unit/color/xyz/convert.spec.ts +18 -0
- package/tests/unit/credential/api-key.spec.ts +37 -0
- package/tests/unit/credential/bearer.spec.ts +23 -0
- package/tests/unit/credential/json-web-token.spec.ts +23 -0
- package/tests/unit/credential/password.spec.ts +41 -0
- package/tests/unit/cron/cron.spec.ts +84 -0
- package/tests/unit/css/class.spec.ts +157 -0
- package/tests/unit/environment/basic.spec.ts +20 -0
- package/tests/unit/environment/device.spec.ts +146 -0
- package/tests/unit/environment/feature.spec.ts +388 -0
- package/tests/unit/environment/geo.spec.ts +111 -0
- package/tests/unit/environment/runtime.spec.ts +364 -0
- package/tests/unit/environment/snapshot.spec.ts +4 -0
- package/tests/unit/environment/variable.spec.ts +190 -0
- package/tests/unit/event/class-event-proxy.spec.ts +225 -0
- package/tests/unit/event/event-manager.spec.ts +246 -0
- package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
- package/tests/unit/exception/browser.spec.ts +213 -0
- package/tests/unit/exception/nodejs.spec.ts +144 -0
- package/tests/unit/exception/normalize.spec.ts +57 -0
- package/tests/unit/form/inputor-controller/base.spec.ts +458 -0
- package/tests/unit/form/inputor-controller/boolean.spec.ts +30 -0
- package/tests/unit/form/inputor-controller/file.spec.ts +27 -0
- package/tests/unit/form/inputor-controller/form.spec.ts +120 -0
- package/tests/unit/form/inputor-controller/helper.spec.ts +67 -0
- package/tests/unit/form/inputor-controller/multi-select.spec.ts +34 -0
- package/tests/unit/form/inputor-controller/number.spec.ts +36 -0
- package/tests/unit/form/inputor-controller/select.spec.ts +49 -0
- package/tests/unit/form/inputor-controller/text.spec.ts +34 -0
- package/tests/unit/http/api/api-core-host.spec.ts +207 -0
- package/tests/unit/http/api/api-schema.spec.ts +120 -0
- package/tests/unit/http/api/api-server.spec.ts +363 -0
- package/tests/unit/http/api/api-test.spec.ts +117 -0
- package/tests/unit/http/api/api.spec.ts +121 -0
- package/tests/unit/http/api-adapter/node-http.spec.ts +191 -0
- package/tests/unit/identifier/id.spec.ts +71 -0
- package/tests/unit/identifier/uuid.spec.ts +85 -0
- package/tests/unit/json/repair.spec.ts +11 -0
- package/tests/unit/log/log-emitter.spec.ts +33 -0
- package/tests/unit/log/log-scheduler.spec.ts +40 -0
- package/tests/unit/log/log-type.spec.ts +7 -0
- package/tests/unit/log/logger.spec.ts +237 -0
- package/tests/unit/openai/openai.spec.ts +64 -0
- package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
- package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
- package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
- package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
- package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
- package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
- package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
- package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
- package/tests/unit/orchestration/dispatching/dispatcher.spec.ts +41 -0
- package/tests/unit/orchestration/dispatching/selector/down-count-selector.spec.ts +81 -0
- package/tests/unit/orchestration/scheduling/scheduler.spec.ts +103 -0
- package/tests/unit/random/base.spec.ts +58 -0
- package/tests/unit/random/random-boolean.spec.ts +25 -0
- package/tests/unit/random/random-integer.spec.ts +32 -0
- package/tests/unit/random/random-number.spec.ts +33 -0
- package/tests/unit/random/random-string.spec.ts +22 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
- package/tests/unit/reactor/preact-signal.spec.ts +1 -2
- package/tests/unit/request/fetch/browser.spec.ts +222 -0
- package/tests/unit/request/fetch/general.spec.ts +43 -0
- package/tests/unit/request/fetch/nodejs.spec.ts +225 -0
- package/tests/unit/request/request/base.spec.ts +385 -0
- package/tests/unit/request/request/general.spec.ts +161 -0
- package/tests/unit/route/router/route.spec.ts +431 -0
- package/tests/unit/route/router/router.spec.ts +407 -0
- package/tests/unit/route/uri/hash.spec.ts +72 -0
- package/tests/unit/route/uri/pathname.spec.ts +147 -0
- package/tests/unit/route/uri/search.spec.ts +107 -0
- package/tests/unit/singleton/singleton.spec.ts +49 -0
- package/tests/unit/socket/client.spec.ts +208 -0
- package/tests/unit/socket/server.spec.ts +135 -0
- package/tests/unit/socket/socket-unit-heartbeat.spec.ts +214 -0
- package/tests/unit/storage/table.spec.ts +620 -0
- package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
- package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
- package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
- package/tests/unit/tube/helper.spec.ts +139 -0
- package/tests/unit/tube/tube.spec.ts +501 -0
- package/.oxlintrc.json +0 -5
- package/src/random/uuid.ts +0 -103
- package/tests/unit/random/uuid.spec.ts +0 -37
package/src/css/class.ts
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 表示以空格分隔的 CSS 类名字串。
|
|
3
|
+
*/
|
|
4
|
+
export type ClassString = string
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 表示按顺序保存的 CSS 类名数组。
|
|
8
|
+
*/
|
|
9
|
+
export type ClassArray = string[]
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 表示以类名为键、以启用状态为值的 CSS 类名对象。
|
|
13
|
+
*
|
|
14
|
+
* 该表示允许保留值为 `false` 的键,以表达已知但当前未启用的类名状态。
|
|
15
|
+
*/
|
|
16
|
+
export type ClassObject = Record<string, boolean>
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 表示 CSS 类名的三种公共表达形式:字符串、数组或对象。
|
|
20
|
+
*/
|
|
21
|
+
export type ClassUnion = ClassString | ClassArray | ClassObject
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 规范化类名字串,使其适合作为统一的字符串表示。
|
|
25
|
+
*
|
|
26
|
+
* 该函数会将 `.` 视为分隔符,将连续空白折叠为一个空格,并移除首尾空白。
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```
|
|
30
|
+
* // Expect: 'mobius-base mobius-theme--light'
|
|
31
|
+
* const example1 = neatenClassString('mobius-base mobius-theme--light')
|
|
32
|
+
*
|
|
33
|
+
* // Expect: 'mobius-base mobius-theme--light'
|
|
34
|
+
* const example2 = neatenClassString('.mobius-base.mobius-theme--light')
|
|
35
|
+
*
|
|
36
|
+
* // Expect: 'mobius-base mobius-theme--light'
|
|
37
|
+
* const example3 = neatenClassString(' .mobius-base mobius-theme--light ')
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export const neatenClassString = (str: string): ClassString => {
|
|
41
|
+
const classString = str.replaceAll('.', ' ').replaceAll(/\s+/g, ' ').trim()
|
|
42
|
+
return classString
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 将类名字串转换为类名数组。
|
|
47
|
+
*
|
|
48
|
+
* 输入会先经过 `neatenClassString` 规范化,再按空格拆分,并移除空项。
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```
|
|
52
|
+
* // Expect: ['mobius-base', 'mobius-theme--light']
|
|
53
|
+
* const example1 = classStringToClassArray('mobius-base mobius-theme--light')
|
|
54
|
+
*
|
|
55
|
+
* // Expect: ['mobius-base', 'mobius-theme--light']
|
|
56
|
+
* const example2 = classStringToClassArray('.mobius-base.mobius-theme--light')
|
|
57
|
+
*
|
|
58
|
+
* // Expect: ['mobius-base', 'mobius-theme--light']
|
|
59
|
+
* const example3 = classStringToClassArray(' .mobius-base mobius-theme--light ')
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const classStringToClassArray = (str: ClassString): ClassArray => {
|
|
63
|
+
const classArray = neatenClassString(str).split(' ').filter(s => s.length !== 0)
|
|
64
|
+
return classArray
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 将类名数组转换为布尔对象表示。
|
|
69
|
+
*
|
|
70
|
+
* 数组中的每个非空类名都会映射为值为 `true` 的对象键。
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```
|
|
74
|
+
* // Expect: { 'mobius-base': true, 'mobius-theme--light': true }
|
|
75
|
+
* const example1 = classArrayToClassObject(['mobius-base', 'mobius-theme--light'])
|
|
76
|
+
*
|
|
77
|
+
* // Expect: { 'mobius-base': true }
|
|
78
|
+
* const example2 = classArrayToClassObject(['mobius-base', ''])
|
|
79
|
+
*
|
|
80
|
+
* // Expect: {}
|
|
81
|
+
* const example3 = classArrayToClassObject([])
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export const classArrayToClassObject = (arr: ClassArray): ClassObject => {
|
|
85
|
+
const classObject: ClassObject = {}
|
|
86
|
+
arr.filter(s => s.length !== 0).forEach(s => {
|
|
87
|
+
classObject[s] = true
|
|
88
|
+
})
|
|
89
|
+
return classObject
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 将类名字串直接转换为布尔对象表示。
|
|
94
|
+
*
|
|
95
|
+
* 该函数会先把字符串拆分为类名数组,再将每个类名映射为值为 `true` 的对象键。
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```
|
|
99
|
+
* // Expect: { 'mobius-base': true, 'mobius-theme--light': true }
|
|
100
|
+
* const example1 = classStringToClassObject('mobius-base mobius-theme--light')
|
|
101
|
+
*
|
|
102
|
+
* // Expect: { 'mobius-base': true, 'mobius-theme--light': true }
|
|
103
|
+
* const example2 = classStringToClassObject('.mobius-base.mobius-theme--light')
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export const classStringToClassObject = (str: ClassString): ClassObject => {
|
|
107
|
+
const classArray = classStringToClassArray(str)
|
|
108
|
+
const classObject = classArrayToClassObject(classArray)
|
|
109
|
+
return classObject
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 将布尔对象表示转换为类名数组。
|
|
114
|
+
*
|
|
115
|
+
* 值为 `false` 的类名和空类名会被忽略。
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```
|
|
119
|
+
* // Expect: ['active', 'primary']
|
|
120
|
+
* const example1 = classObjectToClassArray({ active: true, disabled: false, primary: true })
|
|
121
|
+
*
|
|
122
|
+
* // Expect: ['active']
|
|
123
|
+
* const example2 = classObjectToClassArray({ '': true, active: true, disabled: false })
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export const classObjectToClassArray = (obj: ClassObject): ClassArray => {
|
|
127
|
+
const classArray: string[] = []
|
|
128
|
+
Object.entries(obj)
|
|
129
|
+
.filter(([key, value]) => key.length !== 0 && value)
|
|
130
|
+
.forEach(([key, _]) => {
|
|
131
|
+
classArray.push(key)
|
|
132
|
+
})
|
|
133
|
+
return classArray
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 将类名数组按空格连接为类名字串。
|
|
138
|
+
*
|
|
139
|
+
* 空字符串项会被过滤,以避免产生多余空格。
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```
|
|
143
|
+
* // Expect: 'mobius-base mobius-theme--light'
|
|
144
|
+
* const example1 = classArrayToClassString(['mobius-base', 'mobius-theme--light'])
|
|
145
|
+
*
|
|
146
|
+
* // Expect: 'mobius-base mobius-theme--light'
|
|
147
|
+
* const example2 = classArrayToClassString(['mobius-base', '', 'mobius-theme--light'])
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
export const classArrayToClassString = (arr: ClassArray): ClassString => {
|
|
151
|
+
const classString = arr.filter(s => s.length !== 0).join(' ')
|
|
152
|
+
return classString
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 将布尔对象表示转换为类名字串。
|
|
157
|
+
*
|
|
158
|
+
* 该函数会忽略值为 `false` 的类名和空类名,并保留其余类名的迭代顺序。
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```
|
|
162
|
+
* // Expect: 'active primary'
|
|
163
|
+
* const example1 = classObjectToClassString({ active: true, disabled: false, primary: true })
|
|
164
|
+
*
|
|
165
|
+
* // Expect: 'active'
|
|
166
|
+
* const example2 = classObjectToClassString({ '': true, active: true, disabled: false })
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
export const classObjectToClassString = (obj: ClassObject): ClassString => {
|
|
170
|
+
const classArray = classObjectToClassArray(obj)
|
|
171
|
+
const classString = classArrayToClassString(classArray)
|
|
172
|
+
return classString
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 将任意公共类名表示转换为字符串表示。
|
|
177
|
+
*
|
|
178
|
+
* 如果输入本身已经是字符串,则原样返回;数组和对象会分别经过对应的序列化流程。
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```
|
|
182
|
+
* // Expect: ' .button active '
|
|
183
|
+
* const example1 = toClassString(' .button active ')
|
|
184
|
+
*
|
|
185
|
+
* // Expect: 'button active'
|
|
186
|
+
* const example2 = toClassString(['button', 'active'])
|
|
187
|
+
*
|
|
188
|
+
* // Expect: 'button active'
|
|
189
|
+
* const example3 = toClassString({ button: true, active: true, disabled: false })
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export const toClassString = (tar: ClassUnion): ClassString => {
|
|
193
|
+
if (typeof tar === 'string') {
|
|
194
|
+
return tar
|
|
195
|
+
} else if (Array.isArray(tar)) {
|
|
196
|
+
return classArrayToClassString(tar)
|
|
197
|
+
} else {
|
|
198
|
+
return classObjectToClassString(tar)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 将任意公共类名表示转换为数组表示。
|
|
204
|
+
*
|
|
205
|
+
* 如果输入本身已经是数组,则会在过滤空类名后返回一个浅拷贝,以避免调用方共享同一数组实例。
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```
|
|
209
|
+
* // Expect: ['button', 'active']
|
|
210
|
+
* const example1 = toClassArray('button active')
|
|
211
|
+
*
|
|
212
|
+
* // Expect: ['button', 'active']
|
|
213
|
+
* const example2 = toClassArray(['button', 'active'])
|
|
214
|
+
*
|
|
215
|
+
* // Expect: ['button', 'active']
|
|
216
|
+
* const example3 = toClassArray({ button: true, disabled: false, active: true })
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export const toClassArray = (tar: ClassUnion): ClassArray => {
|
|
220
|
+
if (typeof tar === 'string') {
|
|
221
|
+
return classStringToClassArray(tar)
|
|
222
|
+
} else if (Array.isArray(tar)) {
|
|
223
|
+
return tar.filter(s => s.length !== 0)
|
|
224
|
+
} else {
|
|
225
|
+
return classObjectToClassArray(tar)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 将任意公共类名表示转换为对象表示。
|
|
231
|
+
*
|
|
232
|
+
* 如果输入本身已经是对象,则会在过滤空类名后返回一个浅拷贝,以避免外部直接共享内部结果。
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```
|
|
236
|
+
* // Expect: { button: true, active: true }
|
|
237
|
+
* const example1 = toClassObject('button active')
|
|
238
|
+
*
|
|
239
|
+
* // Expect: { button: true, active: true }
|
|
240
|
+
* const example2 = toClassObject(['button', 'active'])
|
|
241
|
+
*
|
|
242
|
+
* // Expect: { button: true, active: false }
|
|
243
|
+
* const example3 = toClassObject({ button: true, active: false, '': true })
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
export const toClassObject = (tar: ClassUnion): ClassObject => {
|
|
247
|
+
if (typeof tar === 'string') {
|
|
248
|
+
return classStringToClassObject(tar)
|
|
249
|
+
} else if (Array.isArray(tar)) {
|
|
250
|
+
return classArrayToClassObject(tar)
|
|
251
|
+
} else {
|
|
252
|
+
const classObject: ClassObject = {}
|
|
253
|
+
Object.entries(tar).forEach(([key, value]) => {
|
|
254
|
+
if (key.length !== 0) {
|
|
255
|
+
classObject[key] = value
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
return classObject
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* 按目标值的外部表示,将类名集合格式化为相同形态。
|
|
264
|
+
*
|
|
265
|
+
* 该函数适合在内部统一按对象进行计算后,再把结果还原为调用方原本使用的表示。
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```
|
|
269
|
+
* // Expect: 'button active'
|
|
270
|
+
* const example1 = formatClassToTarget('', ['button', 'active'])
|
|
271
|
+
*
|
|
272
|
+
* // Expect: ['button', 'active']
|
|
273
|
+
* const example2 = formatClassToTarget([], 'button active')
|
|
274
|
+
*
|
|
275
|
+
* // Expect: { button: true, active: true }
|
|
276
|
+
* const example3 = formatClassToTarget({}, ['button', 'active'])
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export const formatClassToTarget = <T extends ClassUnion>(target: T, cls: ClassUnion): T => {
|
|
280
|
+
if (typeof target === 'string') {
|
|
281
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
282
|
+
return toClassString(cls) as T
|
|
283
|
+
} else if (Array.isArray(target)) {
|
|
284
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
285
|
+
return toClassArray(cls) as T
|
|
286
|
+
} else {
|
|
287
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
288
|
+
return toClassObject(cls) as T
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* 为类名集合中的每一项补上指定前缀。
|
|
294
|
+
*
|
|
295
|
+
* 已经带有该前缀的类名会保持不变。
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```
|
|
299
|
+
* // Expect: 'pm-button pm-active'
|
|
300
|
+
* const example1 = prefixClassWith('pm-', 'button active')
|
|
301
|
+
*
|
|
302
|
+
* // Expect: ['pm-button', 'pm-active']
|
|
303
|
+
* const example2 = prefixClassWith('pm-', ['button', 'pm-active'])
|
|
304
|
+
*
|
|
305
|
+
* // Expect: { 'pm-button': true, 'pm-active': true }
|
|
306
|
+
* const example3 = prefixClassWith('pm-', { button: true, 'pm-active': true })
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
export const prefixClassWith = <T extends ClassUnion>(prefix: string, cls: T): T => {
|
|
310
|
+
if (typeof cls === 'string') {
|
|
311
|
+
const classArray = classStringToClassArray(cls).map(item =>
|
|
312
|
+
item.startsWith(prefix) ? item : `${prefix}${item}`
|
|
313
|
+
)
|
|
314
|
+
const classString = classArrayToClassString(classArray)
|
|
315
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
316
|
+
return classString as T
|
|
317
|
+
} else if (Array.isArray(cls)) {
|
|
318
|
+
const classArray = cls.filter(item => item.length !== 0).map(item =>
|
|
319
|
+
item.startsWith(prefix) ? item : `${prefix}${item}`
|
|
320
|
+
)
|
|
321
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
322
|
+
return classArray as T
|
|
323
|
+
} else {
|
|
324
|
+
const classObject: ClassObject = {}
|
|
325
|
+
Object.entries(cls).forEach(([key, value]) => {
|
|
326
|
+
if (key.length === 0) {
|
|
327
|
+
return
|
|
328
|
+
}
|
|
329
|
+
const _key = key.startsWith(prefix) ? key : `${prefix}${key}`
|
|
330
|
+
classObject[_key] = value === true
|
|
331
|
+
})
|
|
332
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
333
|
+
return classObject as T
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* 从类名集合中的每一项移除指定前缀。
|
|
339
|
+
*
|
|
340
|
+
* 不带该前缀的类名会保持原样。
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```
|
|
344
|
+
* // Expect: 'button active plain'
|
|
345
|
+
* const example1 = removePrefixOfClass('pm-', 'pm-button pm-active plain')
|
|
346
|
+
*
|
|
347
|
+
* // Expect: ['button', 'plain']
|
|
348
|
+
* const example2 = removePrefixOfClass('pm-', ['pm-button', 'plain'])
|
|
349
|
+
*
|
|
350
|
+
* // Expect: { button: true, plain: false }
|
|
351
|
+
* const example3 = removePrefixOfClass('pm-', { 'pm-button': true, plain: false, 'pm-': true })
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
export const removePrefixOfClass = <T extends ClassUnion>(prefix: string, cls: T): T => {
|
|
355
|
+
if (typeof cls === 'string') {
|
|
356
|
+
const classArray = classStringToClassArray(cls).map(item => {
|
|
357
|
+
if (item.startsWith(prefix)) {
|
|
358
|
+
return item.slice(prefix.length)
|
|
359
|
+
}
|
|
360
|
+
return item
|
|
361
|
+
})
|
|
362
|
+
const classString = classArrayToClassString(classArray)
|
|
363
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
364
|
+
return classString as T
|
|
365
|
+
} else if (Array.isArray(cls)) {
|
|
366
|
+
const classArray = cls.filter(item => item.length !== 0).map(item => {
|
|
367
|
+
if (item.startsWith(prefix)) {
|
|
368
|
+
return item.slice(prefix.length)
|
|
369
|
+
}
|
|
370
|
+
return item
|
|
371
|
+
})
|
|
372
|
+
const filteredClassArray = classArray.filter(item => item.length !== 0)
|
|
373
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
374
|
+
return filteredClassArray as T
|
|
375
|
+
} else {
|
|
376
|
+
const classObject: ClassObject = {}
|
|
377
|
+
Object.entries(cls).forEach(([key, value]) => {
|
|
378
|
+
if (key.length === 0) {
|
|
379
|
+
return
|
|
380
|
+
}
|
|
381
|
+
const _key = key.startsWith(prefix) ? key.slice(prefix.length) : key
|
|
382
|
+
if (_key.length !== 0) {
|
|
383
|
+
classObject[_key] = value === true
|
|
384
|
+
}
|
|
385
|
+
})
|
|
386
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
387
|
+
return classObject as T
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* 向目标类名集合中加入新的类名。
|
|
393
|
+
*
|
|
394
|
+
* 当目标与新增项都包含同名类时,以新增项转换后的对象表示为准。
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```
|
|
398
|
+
* // Expect: 'button active primary'
|
|
399
|
+
* const example1 = addClass('button', 'active primary')
|
|
400
|
+
*
|
|
401
|
+
* // Expect: ['button', 'active', 'primary']
|
|
402
|
+
* const example2 = addClass(['button'], { active: true, primary: true })
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
export const addClass = <T extends ClassUnion>(target: T, added: ClassUnion): T => {
|
|
406
|
+
const targetClassObj = toClassObject(target)
|
|
407
|
+
const addedClassObj = toClassObject(added)
|
|
408
|
+
const resClassObj = { ...targetClassObj, ...addedClassObj }
|
|
409
|
+
const result = formatClassToTarget(target, resClassObj)
|
|
410
|
+
return result
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* 从目标类名集合中移除指定类名。
|
|
415
|
+
*
|
|
416
|
+
* 该函数会把待移除项标记为 `false`,再按目标形态输出结果。
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```
|
|
420
|
+
* // Expect: 'button primary'
|
|
421
|
+
* const example1 = removeClass('button active primary', 'active')
|
|
422
|
+
*
|
|
423
|
+
* // Expect: { button: true, active: false }
|
|
424
|
+
* const example2 = removeClass({ button: true, active: true }, ['active'])
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
export const removeClass = <T extends ClassUnion>(target: T, removed: ClassUnion): T => {
|
|
428
|
+
const targetClassObj = toClassObject(target)
|
|
429
|
+
const removedClassObj = toClassObject(removed)
|
|
430
|
+
Object.keys(removedClassObj).forEach(key => {
|
|
431
|
+
removedClassObj[key] = false
|
|
432
|
+
})
|
|
433
|
+
const resClassObj = { ...targetClassObj, ...removedClassObj }
|
|
434
|
+
const result = formatClassToTarget(target, resClassObj)
|
|
435
|
+
return result
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* 切换目标类名集合中指定类名的启用状态。
|
|
440
|
+
*
|
|
441
|
+
* 已存在的类名会被关闭,不存在的类名会被开启。
|
|
442
|
+
*
|
|
443
|
+
* @example
|
|
444
|
+
* ```
|
|
445
|
+
* // Expect: 'button primary'
|
|
446
|
+
* const example1 = toggleClass('button active', 'active primary')
|
|
447
|
+
*
|
|
448
|
+
* // Expect: { button: true, primary: true }
|
|
449
|
+
* const example2 = toggleClass({ button: true, active: true }, ['active', 'primary'])
|
|
450
|
+
* ```
|
|
451
|
+
*/
|
|
452
|
+
export const toggleClass = <T extends ClassUnion>(target: T, toggled: ClassUnion): T => {
|
|
453
|
+
const targetClassObj = toClassObject(target)
|
|
454
|
+
const toggledClassArr = toClassArray(toggled)
|
|
455
|
+
toggledClassArr.forEach((cls) => {
|
|
456
|
+
// oxlint-disable-next-line strict-boolean-expressions
|
|
457
|
+
targetClassObj[cls] = !targetClassObj[cls]
|
|
458
|
+
})
|
|
459
|
+
const result = formatClassToTarget(target, targetClassObj)
|
|
460
|
+
return result
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* 替换目标类名集合中的类名。
|
|
465
|
+
*
|
|
466
|
+
* `replaced` 支持三种形式:
|
|
467
|
+
* - 字符串:仅移除对应类名。
|
|
468
|
+
* - 字符串数组:逐项移除对应类名。
|
|
469
|
+
* - 元组数组:按 `[from, to]` 的形式逐项替换类名。
|
|
470
|
+
* - 对象:按键值对执行替换,值为空字符串时表示删除。
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* ```
|
|
474
|
+
* // Expect: 'button selected'
|
|
475
|
+
* const example1 = replaceClass('button active', [['active', 'selected']])
|
|
476
|
+
*
|
|
477
|
+
* // Expect: ['button', 'selected']
|
|
478
|
+
* const example2 = replaceClass(['button', 'active'], { active: 'selected' })
|
|
479
|
+
*
|
|
480
|
+
* // Expect: { button: true, active: false }
|
|
481
|
+
* const example3 = replaceClass({ button: true, active: true }, 'active')
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
export const replaceClass = <T extends ClassUnion>(
|
|
485
|
+
target: T,
|
|
486
|
+
replaced: Record<string, string> | string | string[] | Array<[string, string]>,
|
|
487
|
+
): T => {
|
|
488
|
+
if (typeof replaced === 'string') {
|
|
489
|
+
return removeClass(target, replaced)
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const targetClassObj = toClassObject(target)
|
|
493
|
+
|
|
494
|
+
if (Array.isArray(replaced)) {
|
|
495
|
+
for (const item of replaced) {
|
|
496
|
+
if (typeof item === 'string') {
|
|
497
|
+
const fromValue = targetClassObj[item]
|
|
498
|
+
|
|
499
|
+
if (fromValue !== undefined) {
|
|
500
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
501
|
+
delete targetClassObj[item]
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
continue
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const [from, to] = item
|
|
508
|
+
const fromValue = targetClassObj[from]
|
|
509
|
+
|
|
510
|
+
if (fromValue !== undefined) {
|
|
511
|
+
if (to !== '') {
|
|
512
|
+
targetClassObj[to] = fromValue
|
|
513
|
+
}
|
|
514
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
515
|
+
delete targetClassObj[from]
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return formatClassToTarget(target, targetClassObj)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
for (const [from, rawTo] of Object.entries(replaced)) {
|
|
523
|
+
if (typeof rawTo !== 'string') {
|
|
524
|
+
continue
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const fromValue = targetClassObj[from]
|
|
528
|
+
|
|
529
|
+
if (fromValue !== undefined) {
|
|
530
|
+
if (rawTo !== '') {
|
|
531
|
+
targetClassObj[rawTo] = fromValue
|
|
532
|
+
}
|
|
533
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
534
|
+
delete targetClassObj[from]
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return formatClassToTarget(target, targetClassObj)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* 判断目标类名集合是否完整包含另一组类名。
|
|
543
|
+
*
|
|
544
|
+
* 只有当 `contained` 中的每个类名都存在于 `target` 中时,才会返回 `true`。
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```
|
|
548
|
+
* // Expect: true
|
|
549
|
+
* const example1 = containClass('button active', 'button active primary')
|
|
550
|
+
*
|
|
551
|
+
* // Expect: false
|
|
552
|
+
* const example2 = containClass(['button', 'missing'], { button: true, active: true })
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
export const containClass = (contained: ClassUnion, target: ClassUnion): boolean => {
|
|
556
|
+
const containedClassArr = toClassArray(contained)
|
|
557
|
+
const targetClassArr = toClassArray(target)
|
|
558
|
+
return containedClassArr.every(item => targetClassArr.includes(item))
|
|
559
|
+
}
|
package/src/css/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./class.ts"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Drizzle
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as d from "drizzle-orm"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ExtractTablesWithRelations } from "drizzle-orm"
|
|
2
|
+
import { PgDatabase, PgTransaction } from "drizzle-orm/pg-core"
|
|
3
|
+
import type {
|
|
4
|
+
PostgresJsDatabase as RawPostgresJsDatabase,
|
|
5
|
+
PostgresJsTransaction as RawPostgresJsTransaction,
|
|
6
|
+
} from "drizzle-orm/postgres-js"
|
|
7
|
+
|
|
8
|
+
export type PostgresJsNormalDatabase<Schema extends Record<string, unknown> = Record<string, never>>
|
|
9
|
+
= RawPostgresJsDatabase<Schema>
|
|
10
|
+
export type PostgresJsTransactionDatabase<Schema extends Record<string, unknown> = Record<string, never>>
|
|
11
|
+
= RawPostgresJsTransaction<Schema, ExtractTablesWithRelations<Schema>>
|
|
12
|
+
export type PostgresJsDatabase<Schema extends Record<string, unknown> = Record<string, never>>
|
|
13
|
+
= PostgresJsNormalDatabase<Schema> | PostgresJsTransactionDatabase<Schema>
|
|
14
|
+
export interface WithPostgresJsDatabase<Schema extends Record<string, unknown> = Record<string, never>> {
|
|
15
|
+
database: PostgresJsDatabase<Schema>
|
|
16
|
+
}
|
|
17
|
+
export interface WithOptionalPostgresJsDatabase<Schema extends Record<string, unknown> = Record<string, never>> {
|
|
18
|
+
database?: PostgresJsDatabase<Schema> | undefined
|
|
19
|
+
}
|
|
20
|
+
export type WithoutPostgresJsDatabase<T> = Omit<T, "database">
|
|
21
|
+
|
|
22
|
+
export const isPostgresJsNormalDatabase = <Schema extends Record<string, unknown> = Record<string, never>>(
|
|
23
|
+
database: PostgresJsDatabase<Schema>,
|
|
24
|
+
): database is PostgresJsNormalDatabase<Schema> => {
|
|
25
|
+
return database instanceof PgDatabase
|
|
26
|
+
}
|
|
27
|
+
export const isPostgresJsTransactionDatabase = <Schema extends Record<string, unknown> = Record<string, never>>(
|
|
28
|
+
database: PostgresJsDatabase<Schema>,
|
|
29
|
+
): database is PostgresJsTransactionDatabase<Schema> => {
|
|
30
|
+
return database instanceof PgTransaction
|
|
31
|
+
}
|
|
32
|
+
export const autoPostgresJsDatabaseTransaction = async <Result, Schema extends Record<string, unknown> = Record<string, never>>(
|
|
33
|
+
database: PostgresJsDatabase<Schema>,
|
|
34
|
+
run: (database: PostgresJsTransactionDatabase<Schema>) => Promise<Result>,
|
|
35
|
+
): Promise<Result> => {
|
|
36
|
+
// detect transaction database first, then normal database
|
|
37
|
+
// because transaction database is a subclass of normal database
|
|
38
|
+
if (isPostgresJsTransactionDatabase(database)) {
|
|
39
|
+
return await run(database)
|
|
40
|
+
}
|
|
41
|
+
if (isPostgresJsNormalDatabase(database)) {
|
|
42
|
+
return await database.transaction(async (database) => {
|
|
43
|
+
return await run(database)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
throw new Error("Invalid database instance")
|
|
47
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DrizzleTypeError, InferEnum, InferInsertModel, InferSelectModel } from "drizzle-orm"
|
|
2
|
+
import type { PgEnum, PgTableWithColumns } from "drizzle-orm/pg-core"
|
|
3
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"
|
|
4
|
+
|
|
5
|
+
type RemoveNeverValue<T> = {
|
|
6
|
+
[K in keyof T as T[K] extends never ? never : K]: T[K]
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type PreInferModel<T extends Record<string, unknown> = Record<string, never>> = {
|
|
10
|
+
[K in keyof T]: T[K] extends PgTableWithColumns<infer _>
|
|
11
|
+
? InferSelectModel<T[K]>
|
|
12
|
+
: (
|
|
13
|
+
T[K] extends PgEnum<infer __>
|
|
14
|
+
? InferEnum<T[K]>
|
|
15
|
+
: never
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
export type InferModel<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferModel<T>>
|
|
19
|
+
|
|
20
|
+
type PreInferInsert<T extends Record<string, unknown> = Record<string, never>> = {
|
|
21
|
+
[K in keyof T]: T[K] extends PgTableWithColumns<infer _>
|
|
22
|
+
? InferInsertModel<T[K]>
|
|
23
|
+
: never
|
|
24
|
+
}
|
|
25
|
+
export type InferInsert<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferInsert<T>>
|
|
26
|
+
|
|
27
|
+
type PreInferUpdate<T extends Record<string, unknown> = Record<string, never>> = {
|
|
28
|
+
[K in keyof T]: T[K] extends PgTableWithColumns<infer _>
|
|
29
|
+
? Partial<InferSelectModel<T[K]>>
|
|
30
|
+
: (
|
|
31
|
+
T[K] extends PgEnum<infer __>
|
|
32
|
+
? InferEnum<T[K]>
|
|
33
|
+
: never
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
export type InferUpdate<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferUpdate<T>>
|
|
37
|
+
|
|
38
|
+
type GetValidQuery<T extends Record<string, unknown> = Record<string, never>> = Exclude<
|
|
39
|
+
PostgresJsDatabase<T>["query"],
|
|
40
|
+
DrizzleTypeError<string>
|
|
41
|
+
>
|
|
42
|
+
type PreInferWith<T extends Record<string, unknown> = Record<string, never>> = {
|
|
43
|
+
[K in keyof GetValidQuery<T>]: NonNullable<NonNullable<Parameters<GetValidQuery<T>[K]["findMany"]>[0]>["with"]>
|
|
44
|
+
}
|
|
45
|
+
export type InferWith<T extends Record<string, unknown> = Record<string, never>> = RemoveNeverValue<PreInferWith<T>>
|
|
46
|
+
|
|
47
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
48
|
+
export type AnyPgTableWithColumns = PgTableWithColumns<any>
|
|
49
|
+
type PreInferModelFromPgTableWithColumns<T extends AnyPgTableWithColumns> = {
|
|
50
|
+
[K in keyof InferSelectModel<T>]: InferSelectModel<T>[K]
|
|
51
|
+
}
|
|
52
|
+
export type InferModelFromPgTableWithColumns<T extends AnyPgTableWithColumns> = RemoveNeverValue<PreInferModelFromPgTableWithColumns<T>>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Table } from "drizzle-orm"
|
|
2
|
+
import type { Kyselify } from "drizzle-orm/kysely"
|
|
3
|
+
import type { AnyPgTable } from "drizzle-orm/pg-core"
|
|
4
|
+
|
|
5
|
+
export type KyselifyTable<T extends Table> = Kyselify<T>
|
|
6
|
+
export type KyselifyDatabase<T extends Record<string, unknown> = Record<string, never>> = {
|
|
7
|
+
[K in keyof T as T[K] extends AnyPgTable ? T[K]["_"]["name"] : never]: T[K] extends AnyPgTable ? Kyselify<T[K]> : never
|
|
8
|
+
}
|