@wener/common 2.0.5 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/lib/ai/qwen3vl/index.js +1 -1
  2. package/lib/ai/qwen3vl/utils.js +15 -15
  3. package/lib/ai/vision/DocLayoutElementTypeSchema.js +22 -22
  4. package/lib/ai/vision/ImageAnnotationSchema.js +63 -47
  5. package/lib/ai/vision/index.js +2 -2
  6. package/lib/ai/vision/resolveImageAnnotation.js +81 -95
  7. package/lib/cn/ChineseResidentIdNo.js +55 -41
  8. package/lib/cn/ChineseResidentIdNo.mod.js +6 -1
  9. package/lib/cn/ChineseResidentIdNo.test.js +22 -21
  10. package/lib/cn/DivisionCode.js +220 -235
  11. package/lib/cn/DivisionCode.mod.js +6 -1
  12. package/lib/cn/DivisionCode.test.js +92 -121
  13. package/lib/cn/Mod11.js +18 -37
  14. package/lib/cn/Mod31.js +23 -41
  15. package/lib/cn/UnifiedSocialCreditCode.js +143 -137
  16. package/lib/cn/UnifiedSocialCreditCode.mod.js +6 -1
  17. package/lib/cn/UnifiedSocialCreditCode.test.js +21 -15
  18. package/lib/cn/formatChineseAmount.js +46 -71
  19. package/lib/cn/index.js +6 -6
  20. package/lib/cn/mod.js +5 -3
  21. package/lib/cn/parseChineseNumber.js +81 -85
  22. package/lib/cn/parseChineseNumber.test.js +183 -261
  23. package/lib/cn/pinyin/cartesianProduct.js +19 -19
  24. package/lib/cn/pinyin/cartesianProduct.test.js +78 -178
  25. package/lib/cn/pinyin/loader.js +13 -11
  26. package/lib/cn/pinyin/preload.js +2 -1
  27. package/lib/cn/pinyin/toPinyin.test.js +149 -161
  28. package/lib/cn/pinyin/toPinyinPure.js +28 -23
  29. package/lib/cn/pinyin/transform.js +11 -11
  30. package/lib/cn/types.d.js +2 -2
  31. package/lib/consola/createStandardConsolaReporter.js +14 -15
  32. package/lib/consola/formatLogObject.js +149 -133
  33. package/lib/consola/formatLogObject.test.js +167 -178
  34. package/lib/consola/index.js +2 -2
  35. package/lib/data/formatSort.js +14 -12
  36. package/lib/data/formatSort.test.js +33 -33
  37. package/lib/data/index.js +3 -3
  38. package/lib/data/maybeNumber.js +23 -23
  39. package/lib/data/parseSort.js +75 -68
  40. package/lib/data/parseSort.test.js +196 -187
  41. package/lib/data/resolvePagination.js +38 -39
  42. package/lib/data/resolvePagination.test.js +228 -218
  43. package/lib/data/types.d.js +2 -2
  44. package/lib/dayjs/dayjs.js +20 -20
  45. package/lib/dayjs/formatDuration.js +56 -56
  46. package/lib/dayjs/formatDuration.test.js +63 -77
  47. package/lib/dayjs/index.js +4 -4
  48. package/lib/dayjs/parseDuration.js +21 -26
  49. package/lib/dayjs/parseRelativeTime.js +65 -66
  50. package/lib/dayjs/parseRelativeTime.test.js +227 -243
  51. package/lib/dayjs/resolveRelativeTime.js +73 -72
  52. package/lib/dayjs/resolveRelativeTime.test.js +296 -307
  53. package/lib/decimal/index.js +1 -1
  54. package/lib/decimal/parseDecimal.js +12 -12
  55. package/lib/drain3/Drain.js +303 -338
  56. package/lib/drain3/LogCluster.js +25 -25
  57. package/lib/drain3/Node.js +24 -24
  58. package/lib/drain3/TemplateMiner.js +197 -196
  59. package/lib/drain3/index.js +5 -5
  60. package/lib/drain3/persistence/FilePersistence.js +19 -19
  61. package/lib/drain3/persistence/MemoryPersistence.js +8 -8
  62. package/lib/drain3/persistence/PersistenceHandler.js +2 -2
  63. package/lib/drain3/types.js +2 -2
  64. package/lib/emittery/emitter.js +7 -7
  65. package/lib/emittery/index.js +1 -1
  66. package/lib/foundation/schema/SexType.js +15 -12
  67. package/lib/foundation/schema/index.js +1 -1
  68. package/lib/foundation/schema/parseSexType.js +15 -16
  69. package/lib/foundation/schema/types.js +8 -6
  70. package/lib/fs/FileSystemError.js +18 -18
  71. package/lib/fs/IFileSystem.d.js +2 -2
  72. package/lib/fs/MemoryFileSystem.test.js +172 -181
  73. package/lib/fs/createBrowserFileSystem.js +222 -235
  74. package/lib/fs/createMemoryFileSystem.js +472 -510
  75. package/lib/fs/createSandboxFileSystem.js +102 -101
  76. package/lib/fs/createWebDavFileSystem.js +162 -149
  77. package/lib/fs/createWebFileSystem.js +197 -220
  78. package/lib/fs/findMimeType.js +14 -14
  79. package/lib/fs/index.js +7 -7
  80. package/lib/fs/minio/createMinioFileSystem.js +959 -956
  81. package/lib/fs/minio/index.js +1 -1
  82. package/lib/fs/orpc/FileSystemContract.js +57 -57
  83. package/lib/fs/orpc/createContractClientFileSystem.js +88 -88
  84. package/lib/fs/orpc/index.js +2 -2
  85. package/lib/fs/orpc/server/createFileSystemContractImpl.js +62 -60
  86. package/lib/fs/orpc/server/index.js +1 -1
  87. package/lib/fs/s3/createS3MiniFileSystem.js +756 -737
  88. package/lib/fs/s3/index.js +1 -1
  89. package/lib/fs/s3/s3mini.test.js +524 -553
  90. package/lib/fs/scandir.js +56 -56
  91. package/lib/fs/server/createDatabaseFileSystem.js +834 -741
  92. package/lib/fs/server/createNodeFileSystem.js +407 -405
  93. package/lib/fs/server/dbfs.test.js +201 -214
  94. package/lib/fs/server/index.js +1 -1
  95. package/lib/fs/server/loadTestDatabase.js +40 -43
  96. package/lib/fs/tests/runFileSystemTest.js +352 -316
  97. package/lib/fs/types.js +17 -20
  98. package/lib/fs/utils/getFileUrl.js +24 -30
  99. package/lib/fs/utils.js +17 -17
  100. package/lib/fs/webdav/index.js +1 -1
  101. package/lib/index.js +2 -2
  102. package/lib/jsonschema/JsonSchema.js +216 -155
  103. package/lib/jsonschema/JsonSchema.test.js +123 -124
  104. package/lib/jsonschema/forEachJsonSchema.js +41 -41
  105. package/lib/jsonschema/index.js +2 -2
  106. package/lib/jsonschema/types.d.js +2 -2
  107. package/lib/meta/defineFileType.js +32 -38
  108. package/lib/meta/defineInit.js +39 -35
  109. package/lib/meta/defineMetadata.js +37 -34
  110. package/lib/meta/defineMetadata.test.js +13 -12
  111. package/lib/meta/index.js +3 -3
  112. package/lib/orpc/createOpenApiContractClient.js +26 -24
  113. package/lib/orpc/createRpcContractClient.js +37 -31
  114. package/lib/orpc/index.js +2 -2
  115. package/lib/orpc/resolveLinkPlugins.js +25 -25
  116. package/lib/password/PHC.js +187 -189
  117. package/lib/password/PHC.test.js +517 -535
  118. package/lib/password/Password.js +85 -80
  119. package/lib/password/Password.test.js +330 -364
  120. package/lib/password/createArgon2PasswordAlgorithm.js +50 -51
  121. package/lib/password/createBase64PasswordAlgorithm.js +11 -11
  122. package/lib/password/createBcryptPasswordAlgorithm.js +20 -18
  123. package/lib/password/createPBKDF2PasswordAlgorithm.js +65 -52
  124. package/lib/password/createScryptPasswordAlgorithm.js +74 -63
  125. package/lib/password/index.js +5 -5
  126. package/lib/password/server/index.js +1 -1
  127. package/lib/resource/Identifiable.js +2 -2
  128. package/lib/resource/ListQuery.js +42 -42
  129. package/lib/resource/getTitleOfResource.js +5 -5
  130. package/lib/resource/index.js +2 -2
  131. package/lib/resource/schema/AnyResourceSchema.js +91 -89
  132. package/lib/resource/schema/BaseResourceSchema.js +26 -26
  133. package/lib/resource/schema/ResourceActionType.js +117 -115
  134. package/lib/resource/schema/ResourceStatus.js +94 -92
  135. package/lib/resource/schema/ResourceType.js +25 -23
  136. package/lib/resource/schema/index.js +5 -5
  137. package/lib/resource/schema/types.js +86 -55
  138. package/lib/resource/schema/types.test.js +16 -13
  139. package/lib/s3/formatS3Url.js +60 -60
  140. package/lib/s3/formatS3Url.test.js +238 -261
  141. package/lib/s3/index.js +2 -2
  142. package/lib/s3/parseS3Url.js +61 -60
  143. package/lib/s3/parseS3Url.test.js +270 -269
  144. package/lib/schema/SchemaRegistry.js +41 -42
  145. package/lib/schema/SchemaRegistry.mod.js +1 -1
  146. package/lib/schema/TypeSchema.d.js +2 -2
  147. package/lib/schema/createSchemaData.js +113 -67
  148. package/lib/schema/findJsonSchemaByPath.js +28 -23
  149. package/lib/schema/formatZodError.js +112 -131
  150. package/lib/schema/formatZodError.test.js +192 -195
  151. package/lib/schema/getSchemaCache.js +7 -7
  152. package/lib/schema/getSchemaOptions.js +17 -16
  153. package/lib/schema/index.js +6 -6
  154. package/lib/schema/toJsonSchema.js +195 -189
  155. package/lib/schema/toJsonSchema.test.js +34 -26
  156. package/lib/schema/validate.js +105 -96
  157. package/lib/tools/generateSchema.js +40 -40
  158. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +74 -74
  159. package/lib/utils/buildBaseUrl.js +8 -8
  160. package/lib/utils/buildRedactorFormSchema.js +54 -53
  161. package/lib/utils/getEstimateProcessTime.js +24 -19
  162. package/lib/utils/index.js +3 -3
  163. package/lib/utils/resolveFeatureOptions.js +9 -9
  164. package/package.json +14 -14
  165. package/src/ai/vision/index.ts +2 -2
  166. package/src/cn/index.ts +1 -2
  167. package/src/consola/index.ts +1 -1
  168. package/src/data/index.ts +3 -4
  169. package/src/data/resolvePagination.ts +2 -2
  170. package/src/dayjs/formatDuration.ts +8 -9
  171. package/src/dayjs/index.ts +1 -1
  172. package/src/dayjs/parseRelativeTime.ts +1 -1
  173. package/src/dayjs/resolveRelativeTime.ts +1 -1
  174. package/src/drain3/Drain.test.ts +2 -2
  175. package/src/drain3/index.ts +2 -4
  176. package/src/fs/createWebDavFileSystem.ts +2 -7
  177. package/src/fs/createWebFileSystem.ts +1 -1
  178. package/src/fs/index.ts +4 -4
  179. package/src/fs/minio/createMinioFileSystem.ts +2 -2
  180. package/src/fs/minio/index.ts +1 -1
  181. package/src/fs/s3/createS3MiniFileSystem.ts +1 -1
  182. package/src/fs/server/createDatabaseFileSystem.ts +84 -120
  183. package/src/fs/server/dbfs.test.ts +14 -10
  184. package/src/fs/server/index.ts +1 -0
  185. package/src/fs/server/loadTestDatabase.ts +8 -119
  186. package/src/jsonschema/index.ts +1 -1
  187. package/src/meta/index.ts +2 -3
  188. package/src/orm/createSqliteDialect.ts +17 -0
  189. package/src/orm/index.ts +1 -0
  190. package/src/orpc/createOpenApiContractClient.ts +1 -1
  191. package/src/orpc/index.ts +1 -1
  192. package/src/password/createArgon2PasswordAlgorithm.ts +1 -1
  193. package/src/password/index.ts +2 -2
  194. package/src/resource/index.ts +3 -3
  195. package/src/resource/schema/index.ts +4 -4
  196. package/src/s3/index.ts +1 -1
  197. package/src/schema/SchemaRegistry.ts +1 -1
  198. package/src/schema/createSchemaData.ts +1 -1
  199. package/src/schema/findJsonSchemaByPath.ts +1 -1
  200. package/src/schema/index.ts +5 -5
  201. package/src/schema/validate.ts +1 -1
  202. package/src/utils/buildRedactorFormSchema.ts +1 -1
  203. package/src/utils/formatNumber.ts +18 -0
  204. package/src/utils/formatPercent.ts +17 -0
  205. package/src/utils/index.ts +3 -3
  206. package/src/utils/resolveFeatureOptions.ts +1 -1
@@ -1,131 +1,20 @@
1
- import { inspect } from 'node:util';
2
- import type { Options as BetterSqliteOptions } from '@mikro-orm/better-sqlite';
3
- import { Errors, ulid } from '@wener/utils';
4
- import type { Database } from 'better-sqlite3';
1
+ import { MikroORM } from '@mikro-orm/core';
2
+ import { SqliteDriver } from '@mikro-orm/sql';
3
+ import { createSqliteDialect } from '../../orm/createSqliteDialect';
5
4
  import { FileNodeContentEntity, FileNodeMetaEntity } from './createDatabaseFileSystem';
6
5
 
7
- export async function loadTestDatabase({ options }: { options?: BetterSqliteOptions } = {}) {
8
- const { MikroORM: SqliteMikroORM } = await import('@mikro-orm/better-sqlite');
9
-
10
- const orm = await SqliteMikroORM.init({
6
+ export async function loadTestDatabase() {
7
+ const orm = await MikroORM.init({
8
+ driver: SqliteDriver,
11
9
  dbName: ':memory:',
12
10
  entities: [FileNodeContentEntity, FileNodeMetaEntity],
13
- discovery: {
14
- disableDynamicFileAccess: true,
15
- requireEntitiesArray: true,
16
- },
17
- serialization: {
18
- includePrimaryKeys: true,
19
- forceObject: true,
20
- },
21
- findOneOrFailHandler(entityName, where) {
22
- throw Errors.NotFound.asError(`未找到数据: ${entityName} ${inspect(where)}`);
23
- },
24
- findExactlyOneOrFailHandler(entityName, where) {
25
- throw Errors.BadRequest.asError(`错误的数据数量: ${entityName} ${inspect(where)}`);
26
- },
27
- ...options,
11
+ driverOptions: await createSqliteDialect(':memory:'),
28
12
  });
29
13
 
30
- const knex = orm.em.getKnex();
31
- {
32
- const db: Database = await knex.client.acquireConnection();
33
- db.function('ulid', () => ulid());
34
- await knex.client.releaseConnection(db);
35
- }
36
-
37
- // Execute schema creation
38
- for (const stmt of FileSystemSchema.split(';')) {
39
- const sql = stmt.trim();
40
- if (sql) {
41
- await knex.raw(sql);
42
- }
43
- }
14
+ await orm.schema.create();
44
15
 
45
16
  return {
46
17
  orm,
47
18
  em: orm.em.fork(),
48
19
  };
49
20
  }
50
-
51
- export const FileSystemSchema = `
52
- CREATE TABLE IF NOT EXISTS "file_node_meta"
53
- (
54
- -- Base fields
55
- "id" TEXT PRIMARY KEY NOT NULL DEFAULT (ulid()),
56
- "tid" TEXT,
57
- "uid" TEXT,
58
- "eid" TEXT,
59
- "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
60
- "updated_at" TEXT NOT NULL DEFAULT (datetime('now')),
61
- "deleted_at" TEXT,
62
- "attributes" TEXT,
63
- "properties" TEXT,
64
- "extensions" TEXT,
65
-
66
- -- File identification
67
- "filename" TEXT NOT NULL,
68
- "size" INTEGER NOT NULL DEFAULT 0,
69
- "kind" TEXT NOT NULL,
70
-
71
- -- Timestamps
72
- "atime" TEXT NOT NULL,
73
- "btime" TEXT NOT NULL,
74
- "ctime" TEXT NOT NULL,
75
- "mtime" TEXT NOT NULL,
76
-
77
- -- Metadata
78
- "metadata" TEXT NOT NULL DEFAULT '{}',
79
-
80
- -- Hierarchy
81
- "parent_id" TEXT,
82
-
83
- -- Small file content (for files < 64KB)
84
- "content" BLOB,
85
-
86
- FOREIGN KEY ("parent_id") REFERENCES "file_node_meta" ("id")
87
- );
88
-
89
- CREATE INDEX IF NOT EXISTS "idx_file_node_meta_filename" ON "file_node_meta" ("filename");
90
- CREATE INDEX IF NOT EXISTS "idx_file_node_meta_parent_id" ON "file_node_meta" ("parent_id");
91
- CREATE INDEX IF NOT EXISTS "idx_file_node_meta_tid_parent_filename" ON "file_node_meta" ("tid", "parent_id", "filename");
92
-
93
- CREATE TABLE IF NOT EXISTS "file_node_content"
94
- (
95
- -- Base fields
96
- "id" TEXT PRIMARY KEY NOT NULL DEFAULT (ulid()),
97
- "node_id" TEXT NOT NULL UNIQUE,
98
- "tid" TEXT,
99
- "uid" TEXT,
100
- "eid" TEXT,
101
- "created_at" TEXT NOT NULL DEFAULT (datetime('now')),
102
- "updated_at" TEXT NOT NULL DEFAULT (datetime('now')),
103
- "deleted_at" TEXT,
104
- "attributes" TEXT,
105
- "properties" TEXT,
106
- "extensions" TEXT,
107
-
108
- -- Content information
109
- "size" INTEGER NOT NULL,
110
- "content" BLOB,
111
-
112
- -- File properties
113
- "mime_type" TEXT,
114
-
115
- -- Checksums
116
- "md5" TEXT,
117
- "sha256" TEXT,
118
-
119
- -- Content metadata
120
- "text" TEXT,
121
- "width" INTEGER,
122
- "height" INTEGER,
123
-
124
- -- Additional metadata
125
- "metadata" TEXT NOT NULL DEFAULT '{}',
126
-
127
- FOREIGN KEY ("node_id") REFERENCES "file_node_meta" ("id") ON DELETE CASCADE
128
- );
129
-
130
- CREATE INDEX IF NOT EXISTS "idx_file_node_content_node_id" ON "file_node_content" ("node_id");
131
- `;
@@ -1,3 +1,3 @@
1
+ export { forEachJsonSchema } from './forEachJsonSchema';
1
2
  export { JsonSchema } from './JsonSchema';
2
3
  export type { JsonSchemaDef } from './types';
3
- export { forEachJsonSchema } from './forEachJsonSchema';
package/src/meta/index.ts CHANGED
@@ -1,5 +1,4 @@
1
- export { createMetadataKey, defineMetadata, getMetadata } from './defineMetadata';
1
+ export { defineFileType, type FileTypeDef, getFileType } from './defineFileType';
2
2
 
3
3
  export { defineInit, type InitDef, runInit } from './defineInit';
4
-
5
- export { defineFileType, getFileType, type FileTypeDef } from './defineFileType';
4
+ export { createMetadataKey, defineMetadata, getMetadata } from './defineMetadata';
@@ -0,0 +1,17 @@
1
+ import { NodeSqliteDialect } from '@mikro-orm/sql';
2
+
3
+ /**
4
+ * Create a Kysely SQLite dialect based on the current runtime.
5
+ * - Bun: uses bun:sqlite via kysely-bun-sqlite
6
+ * - Node.js 22.5+: uses node:sqlite via NodeSqliteDialect
7
+ */
8
+ export async function createSqliteDialect(dbName: string) {
9
+ if (typeof (globalThis as any).Bun !== 'undefined') {
10
+ // @ts-expect-error bun-only module
11
+ const { BunSqliteDialect } = await import('kysely-bun-sqlite');
12
+ // @ts-expect-error bun-only module
13
+ const { Database } = await import('bun:sqlite');
14
+ return new BunSqliteDialect({ database: new Database(dbName) });
15
+ }
16
+ return new NodeSqliteDialect(dbName);
17
+ }
@@ -0,0 +1 @@
1
+ export { createSqliteDialect } from './createSqliteDialect';
@@ -1,4 +1,4 @@
1
- import { createORPCClient, type ClientContext } from '@orpc/client';
1
+ import { type ClientContext, createORPCClient } from '@orpc/client';
2
2
  import type { LinkFetchClientOptions } from '@orpc/client/fetch';
3
3
  import type { BatchLinkPluginOptions, DedupeRequestsPluginOptions } from '@orpc/client/plugins';
4
4
  import type { StandardLinkPlugin } from '@orpc/client/standard';
package/src/orpc/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { createRpcContractClient } from './createRpcContractClient';
2
1
  export { createOpenApiContractClient } from './createOpenApiContractClient';
2
+ export { createRpcContractClient } from './createRpcContractClient';
@@ -1,4 +1,4 @@
1
- import { maybeFunction, type MaybeFunction, type MaybePromise } from '@wener/utils';
1
+ import { type MaybeFunction, type MaybePromise, maybeFunction } from '@wener/utils';
2
2
  import type { Password } from './Password';
3
3
 
4
4
  type Provide = {
@@ -1,5 +1,5 @@
1
- export { PHC } from './PHC';
2
- export { Password } from './Password';
3
1
  export { createArgon2PasswordAlgorithm } from './createArgon2PasswordAlgorithm';
4
2
  export { createBase64PasswordAlgorithm } from './createBase64PasswordAlgorithm';
5
3
  export { createBcryptPasswordAlgorithm } from './createBcryptPasswordAlgorithm';
4
+ export { Password } from './Password';
5
+ export { PHC } from './PHC';
@@ -1,4 +1,4 @@
1
- export type { AnyResource } from './schema/AnyResourceSchema';
2
- export type { Identifiable } from './Identifiable';
3
1
  export { getTitleOfResource } from './getTitleOfResource';
4
- export { type ListQueryInput, type ListQuery, resolveListQuery, ListQuerySchema } from './ListQuery';
2
+ export type { Identifiable } from './Identifiable';
3
+ export { type ListQuery, type ListQueryInput, ListQuerySchema, resolveListQuery } from './ListQuery';
4
+ export type { AnyResource } from './schema/AnyResourceSchema';
@@ -1,5 +1,5 @@
1
- export { ResourceStatus, ResourceStatusSchema } from './ResourceStatus';
2
- export { ResourceActionType, ResourceActionTypeSchema, ResourceActionDataSchema } from './ResourceActionType';
3
- export { AnyResourceSchema, type AnyResource } from './AnyResourceSchema';
4
- export { rz, type EnumValues } from './types';
1
+ export { type AnyResource, AnyResourceSchema } from './AnyResourceSchema';
5
2
  export { BaseResourceSchema } from './BaseResourceSchema';
3
+ export { ResourceActionDataSchema, ResourceActionType, ResourceActionTypeSchema } from './ResourceActionType';
4
+ export { ResourceStatus, ResourceStatusSchema } from './ResourceStatus';
5
+ export { type EnumValues, rz } from './types';
package/src/s3/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { parseS3Url, type ParseS3UrlOptions } from './parseS3Url';
2
1
  export { formatS3Url } from './formatS3Url';
2
+ export { type ParseS3UrlOptions, parseS3Url } from './parseS3Url';
@@ -1,6 +1,6 @@
1
1
  import { getGlobalStates } from '@wener/utils';
2
2
  import type { JsonSchemaDef } from '../jsonschema';
3
- import { toJsonSchema, type SchemaOutput, type TypeSchema } from './index';
3
+ import { type SchemaOutput, type TypeSchema, toJsonSchema } from './index';
4
4
 
5
5
  export namespace SchemaRegistry {
6
6
  const types = getGlobalStates('@wener/common/resource/schema/SchemaRegistry', () => new Map<string, JsonSchemaDef>());
@@ -1,7 +1,7 @@
1
1
  import { match, P } from 'ts-pattern';
2
2
  import type { JsonSchemaDef } from '../jsonschema';
3
- import { toJsonSchema } from './toJsonSchema';
4
3
  import type { SchemaOutput, TypeSchema } from './TypeSchema';
4
+ import { toJsonSchema } from './toJsonSchema';
5
5
 
6
6
  export function createSchemaData<S extends TypeSchema>(
7
7
  ts: S,
@@ -1,6 +1,6 @@
1
1
  import { firstOfMaybeArray } from '@wener/utils';
2
- import { toJsonSchema } from './toJsonSchema';
3
2
  import type { TypeSchema } from './TypeSchema';
3
+ import { toJsonSchema } from './toJsonSchema';
4
4
 
5
5
  export function findJsonSchemaByPath(schema: TypeSchema, objectPath: string) {
6
6
  schema = toJsonSchema(schema);
@@ -1,7 +1,7 @@
1
- export type * from './TypeSchema';
2
- export { isJsonSchema, isZodSchema, isTypeBoxSchema, validate, parseData, type ValidationResult } from './validate';
3
- export { getSchemaOptions, getSchemaOptionLabel } from './getSchemaOptions';
4
- export { toJsonSchema } from './toJsonSchema';
5
- export { findJsonSchemaByPath } from './findJsonSchemaByPath';
6
1
  export { createSchemaData } from './createSchemaData';
2
+ export { findJsonSchemaByPath } from './findJsonSchemaByPath';
3
+ export { getSchemaOptionLabel, getSchemaOptions } from './getSchemaOptions';
7
4
  export { SchemaRegistry } from './SchemaRegistry';
5
+ export type * from './TypeSchema';
6
+ export { toJsonSchema } from './toJsonSchema';
7
+ export { isJsonSchema, isTypeBoxSchema, isZodSchema, parseData, type ValidationResult, validate } from './validate';
@@ -1,4 +1,4 @@
1
- import { Kind as TypeBoxKind, type TSchema } from '@sinclair/typebox';
1
+ import { type TSchema, Kind as TypeBoxKind } from '@sinclair/typebox';
2
2
  import '@sinclair/typebox';
3
3
  import { TypeCompiler } from '@sinclair/typebox/compiler';
4
4
  import { ifPresent } from '@wener/utils';
@@ -1,5 +1,5 @@
1
1
  import { forEachJsonSchema, type JsonSchemaDef } from '../jsonschema';
2
- import { toJsonSchema, type TypeSchema } from '../schema';
2
+ import { type TypeSchema, toJsonSchema } from '../schema';
3
3
 
4
4
  export const RedactedText = '[redacted]';
5
5
 
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Format a number, removing trailing zeros
3
+ * @param value - number or string convertible to number
4
+ * @param decimals - decimal places to keep, default 2
5
+ *
6
+ * @example
7
+ * formatNumber(1.50) // "1.5"
8
+ * formatNumber(1.00) // "1"
9
+ * formatNumber(1.234) // "1.23"
10
+ */
11
+ export function formatNumber(value: number | string, decimals = 2): string {
12
+ const num = typeof value === 'string' ? Number.parseFloat(value) : value;
13
+ if (Number.isNaN(num)) return String(value);
14
+ return num
15
+ .toFixed(decimals)
16
+ .replace(/(\.\d*?)0+$/, '$1')
17
+ .replace(/\.$/, '');
18
+ }
@@ -0,0 +1,17 @@
1
+ import { formatNumber } from './formatNumber';
2
+
3
+ /**
4
+ * Format a percentage, removing trailing zeros
5
+ * @param value - number (0-1 or 0-100)
6
+ * @param decimals - decimal places to keep, default 2
7
+ * @param isRatio - whether value is a ratio (0-1), default false
8
+ *
9
+ * @example
10
+ * formatPercent(0.5, 2, true) // "50"
11
+ * formatPercent(50.00) // "50"
12
+ * formatPercent(33.33) // "33.33"
13
+ */
14
+ export function formatPercent(value: number, decimals = 2, isRatio = false): string {
15
+ const percent = isRatio ? value * 100 : value;
16
+ return formatNumber(percent, decimals);
17
+ }
@@ -1,5 +1,5 @@
1
- export { getEstimateProcessTime } from './getEstimateProcessTime';
1
+ export { buildBaseUrl } from './buildBaseUrl';
2
2
 
3
3
  export { buildRedactorFormSchema } from './buildRedactorFormSchema';
4
-
5
- export { buildBaseUrl } from './buildBaseUrl';
4
+ export { formatNumber } from './formatNumber';
5
+ export { getEstimateProcessTime } from './getEstimateProcessTime';
@@ -1,4 +1,4 @@
1
- import { maybeFunction, type MaybeFunction } from '@wener/utils';
1
+ import { type MaybeFunction, maybeFunction } from '@wener/utils';
2
2
 
3
3
  export function resolveFeatureOptions<T>(
4
4
  value: boolean | T | undefined | null,