@wener/common 1.0.4 → 2.0.1

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 (151) hide show
  1. package/lib/cn/DivisionCode.js +55 -32
  2. package/lib/cn/DivisionCode.test.js +140 -0
  3. package/lib/cn/Mod11Checksum.js +80 -37
  4. package/lib/cn/Mod31Checksum.js +89 -40
  5. package/lib/cn/ResidentIdentityCardNumber.js +16 -16
  6. package/lib/cn/ResidentIdentityCardNumber.test.js +21 -0
  7. package/lib/cn/UnifiedSocialCreditCode.js +32 -26
  8. package/lib/cn/UnifiedSocialCreditCode.test.js +16 -0
  9. package/lib/cn/formatDate.js +5 -7
  10. package/lib/cn/index.js +0 -1
  11. package/lib/cn/parseSex.js +0 -2
  12. package/lib/cn/types.d.js +0 -2
  13. package/lib/consola/createStandardConsolaReporter.js +18 -0
  14. package/lib/consola/formatLogObject.js +226 -0
  15. package/lib/consola/index.js +2 -0
  16. package/lib/data/formatSort.js +5 -6
  17. package/lib/data/formatSort.test.js +34 -0
  18. package/lib/data/index.js +0 -1
  19. package/lib/data/maybeNumber.js +11 -5
  20. package/lib/data/parseSort.js +28 -22
  21. package/lib/data/parseSort.test.js +188 -0
  22. package/lib/data/resolvePagination.js +27 -16
  23. package/lib/data/resolvePagination.test.js +232 -0
  24. package/lib/data/types.d.js +0 -2
  25. package/lib/index.js +0 -1
  26. package/lib/jsonschema/JsonSchema.js +80 -54
  27. package/lib/jsonschema/JsonSchema.test.js +137 -0
  28. package/lib/jsonschema/index.js +0 -1
  29. package/lib/jsonschema/types.d.js +5 -3
  30. package/lib/meta/defineFileType.js +103 -20
  31. package/lib/meta/defineInit.js +250 -31
  32. package/lib/meta/defineMetadata.js +140 -24
  33. package/lib/meta/defineMetadata.test.js +13 -0
  34. package/lib/meta/index.js +0 -1
  35. package/lib/password/PHC.js +87 -63
  36. package/lib/password/PHC.test.js +539 -0
  37. package/lib/password/Password.js +291 -29
  38. package/lib/password/Password.test.js +362 -0
  39. package/lib/password/createArgon2PasswordAlgorithm.js +191 -35
  40. package/lib/password/createBase64PasswordAlgorithm.js +141 -8
  41. package/lib/password/createBcryptPasswordAlgorithm.js +168 -13
  42. package/lib/password/createPBKDF2PasswordAlgorithm.js +228 -46
  43. package/lib/password/createScryptPasswordAlgorithm.js +211 -55
  44. package/lib/password/index.js +0 -1
  45. package/lib/password/server/index.js +0 -1
  46. package/lib/resource/Identifiable.js +1 -0
  47. package/lib/resource/getTitleOfResource.js +10 -0
  48. package/lib/resource/index.js +1 -0
  49. package/lib/resource/schema/AnyResourceSchema.js +89 -0
  50. package/lib/resource/schema/BaseResourceSchema.js +29 -0
  51. package/lib/resource/schema/ResourceActionType.js +118 -0
  52. package/lib/resource/schema/ResourceStatus.js +93 -0
  53. package/lib/resource/schema/ResourceType.js +24 -0
  54. package/lib/resource/schema/SchemaRegistry.js +38 -0
  55. package/lib/resource/schema/SexType.js +10 -0
  56. package/lib/resource/schema/types.js +89 -0
  57. package/lib/resource/schema/types.test.js +14 -0
  58. package/lib/schema/TypeSchema.d.js +1 -0
  59. package/lib/schema/createSchemaData.js +173 -0
  60. package/lib/schema/findJsonSchemaByPath.js +49 -0
  61. package/lib/schema/getSchemaCache.js +11 -0
  62. package/lib/schema/getSchemaOptions.js +24 -0
  63. package/lib/schema/index.js +5 -0
  64. package/lib/schema/toJsonSchema.js +441 -0
  65. package/lib/schema/toJsonSchema.test.js +27 -0
  66. package/lib/schema/validate.js +124 -0
  67. package/lib/search/AdvanceSearch.js +0 -1
  68. package/lib/search/AdvanceSearch.test.js +435 -0
  69. package/lib/search/formatAdvanceSearch.js +41 -27
  70. package/lib/search/index.js +0 -1
  71. package/lib/search/optimizeAdvanceSearch.js +79 -25
  72. package/lib/search/parseAdvanceSearch.js +5 -5
  73. package/lib/search/parser.d.js +0 -2
  74. package/lib/search/parser.js +97 -74
  75. package/lib/search/types.d.js +0 -2
  76. package/lib/tools/generateSchema.js +201 -0
  77. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +143 -55
  78. package/package.json +30 -9
  79. package/src/consola/createStandardConsolaReporter.ts +31 -0
  80. package/src/consola/formatLogObject.ts +171 -0
  81. package/src/consola/index.ts +2 -0
  82. package/src/data/maybeNumber.ts +5 -1
  83. package/src/data/resolvePagination.test.ts +1 -1
  84. package/src/data/resolvePagination.ts +18 -7
  85. package/src/data/types.d.ts +12 -0
  86. package/src/jsonschema/JsonSchema.test.ts +17 -0
  87. package/src/jsonschema/JsonSchema.ts +4 -4
  88. package/src/jsonschema/types.d.ts +63 -12
  89. package/src/resource/Identifiable.ts +3 -0
  90. package/src/resource/getTitleOfResource.tsx +6 -0
  91. package/src/resource/index.ts +3 -0
  92. package/src/resource/schema/AnyResourceSchema.ts +113 -0
  93. package/src/resource/schema/BaseResourceSchema.ts +32 -0
  94. package/src/resource/schema/ResourceActionType.ts +123 -0
  95. package/src/resource/schema/ResourceStatus.ts +94 -0
  96. package/src/resource/schema/ResourceType.ts +25 -0
  97. package/src/resource/schema/SchemaRegistry.ts +42 -0
  98. package/src/resource/schema/SexType.ts +13 -0
  99. package/src/resource/schema/types.test.ts +18 -0
  100. package/src/resource/schema/types.ts +105 -0
  101. package/src/schema/TypeSchema.d.ts +32 -0
  102. package/src/schema/createSchemaData.ts +81 -0
  103. package/src/schema/findJsonSchemaByPath.ts +37 -0
  104. package/src/schema/getSchemaCache.ts +21 -0
  105. package/src/schema/getSchemaOptions.ts +24 -0
  106. package/src/schema/index.ts +6 -0
  107. package/src/schema/toJsonSchema.test.ts +37 -0
  108. package/src/schema/toJsonSchema.ts +200 -0
  109. package/src/schema/validate.ts +135 -0
  110. package/src/tools/generateSchema.ts +39 -0
  111. package/lib/cn/DivisionCode.js.map +0 -1
  112. package/lib/cn/Mod11Checksum.js.map +0 -1
  113. package/lib/cn/Mod31Checksum.js.map +0 -1
  114. package/lib/cn/ResidentIdentityCardNumber.js.map +0 -1
  115. package/lib/cn/UnifiedSocialCreditCode.js.map +0 -1
  116. package/lib/cn/formatDate.js.map +0 -1
  117. package/lib/cn/index.js.map +0 -1
  118. package/lib/cn/parseSex.js.map +0 -1
  119. package/lib/cn/types.d.js.map +0 -1
  120. package/lib/data/formatSort.js.map +0 -1
  121. package/lib/data/index.js.map +0 -1
  122. package/lib/data/maybeNumber.js.map +0 -1
  123. package/lib/data/parseSort.js.map +0 -1
  124. package/lib/data/resolvePagination.js.map +0 -1
  125. package/lib/data/types.d.js.map +0 -1
  126. package/lib/index.js.map +0 -1
  127. package/lib/jsonschema/JsonSchema.js.map +0 -1
  128. package/lib/jsonschema/index.js.map +0 -1
  129. package/lib/jsonschema/types.d.js.map +0 -1
  130. package/lib/meta/defineFileType.js.map +0 -1
  131. package/lib/meta/defineInit.js.map +0 -1
  132. package/lib/meta/defineMetadata.js.map +0 -1
  133. package/lib/meta/index.js.map +0 -1
  134. package/lib/password/PHC.js.map +0 -1
  135. package/lib/password/Password.js.map +0 -1
  136. package/lib/password/createArgon2PasswordAlgorithm.js.map +0 -1
  137. package/lib/password/createBase64PasswordAlgorithm.js.map +0 -1
  138. package/lib/password/createBcryptPasswordAlgorithm.js.map +0 -1
  139. package/lib/password/createPBKDF2PasswordAlgorithm.js.map +0 -1
  140. package/lib/password/createScryptPasswordAlgorithm.js.map +0 -1
  141. package/lib/password/index.js.map +0 -1
  142. package/lib/password/server/index.js.map +0 -1
  143. package/lib/search/AdvanceSearch.js.map +0 -1
  144. package/lib/search/formatAdvanceSearch.js.map +0 -1
  145. package/lib/search/index.js.map +0 -1
  146. package/lib/search/optimizeAdvanceSearch.js.map +0 -1
  147. package/lib/search/parseAdvanceSearch.js.map +0 -1
  148. package/lib/search/parser.d.js.map +0 -1
  149. package/lib/search/parser.js.map +0 -1
  150. package/lib/search/types.d.js.map +0 -1
  151. package/lib/tools/renderJsonSchemaToMarkdownDoc.js.map +0 -1
@@ -0,0 +1,123 @@
1
+ import { z } from 'zod/v4';
2
+ import type { EnumValues } from './types';
3
+
4
+ export const ResourceActionType = Object.freeze({
5
+ __proto__: null,
6
+ Approve: 'Approve',
7
+ AssignOwner: 'AssignOwner',
8
+ Bind: 'Bind',
9
+ BindCustomer: 'BindCustomer',
10
+ BindEntity: 'BindEntity',
11
+ BindUser: 'BindUser',
12
+ Cancel: 'Cancel',
13
+ ChangePassword: 'ChangePassword',
14
+ ClaimOwner: 'ClaimOwner',
15
+ Close: 'Close',
16
+ Communicate: 'Communicate',
17
+ Complete: 'Complete',
18
+ Create: 'Create',
19
+ Delete: 'Delete',
20
+ Deny: 'Deny',
21
+ Disable: 'Disable',
22
+ Download: 'Download',
23
+ Edit: 'Edit',
24
+ Enable: 'Enable',
25
+ List: 'List',
26
+ Login: 'Login',
27
+ Logout: 'Logout',
28
+ Manage: 'Manage',
29
+ Publish: 'Publish',
30
+ Purge: 'Purge',
31
+ Read: 'Read',
32
+ Reject: 'Reject',
33
+ ReleaseOwner: 'ReleaseOwner',
34
+ ResetPassword: 'ResetPassword',
35
+ ReturnForRevision: 'ReturnForRevision',
36
+ Revise: 'Revise',
37
+ SaveDraft: 'SaveDraft',
38
+ Signup: 'Signup',
39
+ Submit: 'Submit',
40
+ SubmitAgency: 'SubmitAgency',
41
+ SubmitVendor: 'SubmitVendor',
42
+ Suspend: 'Suspend',
43
+ Terminate: 'Terminate',
44
+ Timeout: 'Timeout',
45
+ Unbind: 'Unbind',
46
+ UnbindCustomer: 'UnbindCustomer',
47
+ UnbindEntity: 'UnbindEntity',
48
+ UnbindUser: 'UnbindUser',
49
+ Undelete: 'Undelete',
50
+ Unpublish: 'Unpublish',
51
+ Update: 'Update',
52
+ UpdateNotes: 'UpdateNotes',
53
+ UpdateTags: 'UpdateTags',
54
+ Upload: 'Upload',
55
+ Validate: 'Validate',
56
+ View: 'View',
57
+ Write: 'Write',
58
+ } as const);
59
+ export type ResourceActionType = EnumValues<typeof ResourceActionType>;
60
+ export const ResourceActionTypeSchema = z
61
+ .union([
62
+ z.literal(ResourceActionType.Approve).describe('批准'),
63
+ z.literal(ResourceActionType.AssignOwner).describe('分配负责人'),
64
+ z.literal(ResourceActionType.Bind).describe('绑定'),
65
+ z.literal(ResourceActionType.BindCustomer).describe('绑定客户'),
66
+ z.literal(ResourceActionType.BindEntity).describe('绑定实体'),
67
+ z.literal(ResourceActionType.BindUser).describe('绑定用户'),
68
+ z.literal(ResourceActionType.Cancel).describe('取消'),
69
+ z.literal(ResourceActionType.ChangePassword).describe('修改密码'),
70
+ z.literal(ResourceActionType.ClaimOwner).describe('认领负责人'),
71
+ z.literal(ResourceActionType.Close).describe('关闭'),
72
+ z.literal(ResourceActionType.Communicate).describe('沟通'),
73
+ z.literal(ResourceActionType.Complete).describe('完成'),
74
+ z.literal(ResourceActionType.Create).describe('创建'),
75
+ z.literal(ResourceActionType.Delete).describe('删除'),
76
+ z.literal(ResourceActionType.Deny).describe('拒绝'),
77
+ z.literal(ResourceActionType.Disable).describe('禁用'),
78
+ z.literal(ResourceActionType.Download).describe('下载'),
79
+ z.literal(ResourceActionType.Edit).describe('编辑'),
80
+ z.literal(ResourceActionType.Enable).describe('启用'),
81
+ z.literal(ResourceActionType.List).describe('列表'),
82
+ z.literal(ResourceActionType.Login).describe('登录'),
83
+ z.literal(ResourceActionType.Logout).describe('登出'),
84
+ z.literal(ResourceActionType.Manage).describe('管理'),
85
+ z.literal(ResourceActionType.Publish).describe('发布'),
86
+ z.literal(ResourceActionType.Purge).describe('彻底删除'),
87
+ z.literal(ResourceActionType.Read).describe('读取'),
88
+ z.literal(ResourceActionType.Reject).describe('驳回'),
89
+ z.literal(ResourceActionType.ReleaseOwner).describe('释放负责人'),
90
+ z.literal(ResourceActionType.ResetPassword).describe('重置密码'),
91
+ z.literal(ResourceActionType.ReturnForRevision).describe('退回修订'),
92
+ z.literal(ResourceActionType.Revise).describe('修订'),
93
+ z.literal(ResourceActionType.SaveDraft).describe('保存草稿'),
94
+ z.literal(ResourceActionType.Signup).describe('注册'),
95
+ z.literal(ResourceActionType.Submit).describe('提交'),
96
+ z.literal(ResourceActionType.SubmitAgency).describe('提交机构'),
97
+ z.literal(ResourceActionType.SubmitVendor).describe('提交供应商'),
98
+ z.literal(ResourceActionType.Suspend).describe('暂停'),
99
+ z.literal(ResourceActionType.Terminate).describe('终止'),
100
+ z.literal(ResourceActionType.Timeout).describe('超时'),
101
+ z.literal(ResourceActionType.Unbind).describe('解绑'),
102
+ z.literal(ResourceActionType.UnbindCustomer).describe('解绑客户'),
103
+ z.literal(ResourceActionType.UnbindEntity).describe('解绑实体'),
104
+ z.literal(ResourceActionType.UnbindUser).describe('解绑用户'),
105
+ z.literal(ResourceActionType.Undelete).describe('恢复删除'),
106
+ z.literal(ResourceActionType.Unpublish).describe('取消发布'),
107
+ z.literal(ResourceActionType.Update).describe('更新'),
108
+ z.literal(ResourceActionType.UpdateNotes).describe('修改备注'),
109
+ z.literal(ResourceActionType.UpdateNotes).describe('更新备注'),
110
+ z.literal(ResourceActionType.UpdateTags).describe('更新标签'),
111
+ z.literal(ResourceActionType.Upload).describe('上传'),
112
+ z.literal(ResourceActionType.Validate).describe('校验'),
113
+ z.literal(ResourceActionType.View).describe('查看'),
114
+ z.literal(ResourceActionType.Write).describe('写入'),
115
+ ])
116
+ .meta({
117
+ title: 'ResourceAction',
118
+ description: '资源操作',
119
+ type: 'string',
120
+ });
121
+ export const ResourceActionDataSchema = z.object({
122
+ reason: z.string().optional().describe('操作原因'),
123
+ });
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod/v4';
2
+ import type { EnumValues } from './types';
3
+
4
+ export const ResourceStatus = Object.freeze({
5
+ __proto__: null,
6
+ Active: 'Active',
7
+ Approved: 'Approved',
8
+ Cancelled: 'Cancelled',
9
+ Closed: 'Closed',
10
+ Completed: 'Completed',
11
+ Confirmed: 'Confirmed',
12
+ Contacted: 'Contacted',
13
+ Contacting: 'Contacting',
14
+ Deleted: 'Deleted',
15
+ Denied: 'Denied',
16
+ Disabled: 'Disabled',
17
+ Disqualified: 'Disqualified',
18
+ Draft: 'Draft',
19
+ Enabled: 'Enabled',
20
+ Expired: 'Expired',
21
+ Failed: 'Failed',
22
+ InProgress: 'InProgress',
23
+ Inactive: 'Inactive',
24
+ Initial: 'Initial',
25
+ Lost: 'Lost',
26
+ New: 'New',
27
+ Nurturing: 'Nurturing',
28
+ OnHold: 'OnHold',
29
+ Open: 'Open',
30
+ Overdue: 'Overdue',
31
+ Paid: 'Paid',
32
+ PartiallyPaid: 'PartiallyPaid',
33
+ Pending: 'Pending',
34
+ PendingAcceptance: 'PendingAcceptance',
35
+ PendingApproval: 'PendingApproval',
36
+ PendingConfirmation: 'PendingConfirmation',
37
+ PendingResubmission: 'PendingResubmission',
38
+ Posted: 'Posted',
39
+ Published: 'Published',
40
+ Qualified: 'Qualified',
41
+ Rejected: 'Rejected',
42
+ Submitted: 'Submitted',
43
+ Suspended: 'Suspended',
44
+ Terminated: 'Terminated',
45
+ Unqualified: 'Unqualified',
46
+ Void: 'Void',
47
+ Won: 'Won',
48
+ } as const);
49
+ export type ResourceStatus = EnumValues<typeof ResourceStatus>;
50
+ export const ResourceStatusSchema = z
51
+ .union([
52
+ z.literal(ResourceStatus.Active).describe('活跃'),
53
+ z.literal(ResourceStatus.Approved).describe('已通过'),
54
+ z.literal(ResourceStatus.Cancelled).describe('已取消'),
55
+ z.literal(ResourceStatus.Closed).describe('已关闭'),
56
+ z.literal(ResourceStatus.Completed).describe('已完成'),
57
+ z.literal(ResourceStatus.Confirmed).describe('已确认'),
58
+ z.literal(ResourceStatus.Contacted).describe('已联系'),
59
+ z.literal(ResourceStatus.Contacting).describe('联系中'),
60
+ z.literal(ResourceStatus.Deleted).describe('已删除'),
61
+ z.literal(ResourceStatus.Denied).describe('已拒绝'),
62
+ z.literal(ResourceStatus.Disabled).describe('已禁用'),
63
+ z.literal(ResourceStatus.Disqualified).describe('不合格'),
64
+ z.literal(ResourceStatus.Draft).describe('草稿'),
65
+ z.literal(ResourceStatus.Enabled).describe('已启用'),
66
+ z.literal(ResourceStatus.Expired).describe('已过期'),
67
+ z.literal(ResourceStatus.InProgress).describe('进行中'),
68
+ z.literal(ResourceStatus.Inactive).describe('停用'),
69
+ z.literal(ResourceStatus.Initial).describe('初始'),
70
+ z.literal(ResourceStatus.Lost).describe('已失去'),
71
+ z.literal(ResourceStatus.New).describe('新建'),
72
+ z.literal(ResourceStatus.Nurturing).describe('培育中'),
73
+ z.literal(ResourceStatus.OnHold).describe('搁置'),
74
+ z.literal(ResourceStatus.Open).describe('开放'),
75
+ z.literal(ResourceStatus.Overdue).describe('逾期'),
76
+ z.literal(ResourceStatus.Paid).describe('已支付'),
77
+ z.literal(ResourceStatus.PartiallyPaid).describe('部分支付'),
78
+ z.literal(ResourceStatus.Pending).describe('待审核'),
79
+ z.literal(ResourceStatus.PendingAcceptance).describe('待接受'),
80
+ z.literal(ResourceStatus.PendingApproval).describe('待批准'),
81
+ z.literal(ResourceStatus.PendingConfirmation).describe('待确认'),
82
+ z.literal(ResourceStatus.PendingResubmission).describe('待重新提交'),
83
+ z.literal(ResourceStatus.Posted).describe('已过账'),
84
+ z.literal(ResourceStatus.Published).describe('已发布'),
85
+ z.literal(ResourceStatus.Qualified).describe('已合格'),
86
+ z.literal(ResourceStatus.Rejected).describe('已驳回'),
87
+ z.literal(ResourceStatus.Submitted).describe('已提交'),
88
+ z.literal(ResourceStatus.Suspended).describe('暂停'),
89
+ z.literal(ResourceStatus.Terminated).describe('终止'),
90
+ z.literal(ResourceStatus.Unqualified).describe('未达标'),
91
+ z.literal(ResourceStatus.Void).describe('作废'),
92
+ z.literal(ResourceStatus.Won).describe('已赢得'),
93
+ ])
94
+ .meta({ title: 'ResourceStatus', description: '资源状态', type: 'string' });
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod/v4';
2
+ import type { EnumValues } from './types';
3
+
4
+ export const ResourceType = Object.freeze({
5
+ __proto__: null,
6
+ User: 'User',
7
+ Customer: 'Customer',
8
+ Contact: 'Contact',
9
+ Account: 'Account',
10
+ Order: 'Order',
11
+ Lead: 'Lead',
12
+ Opportunity: 'Opportunity',
13
+ } as const);
14
+ export type ResourceType = EnumValues<typeof ResourceType>;
15
+ export const ResourceTypeSchema = z
16
+ .union([
17
+ z.literal(ResourceType.User).describe('用户'),
18
+ z.literal(ResourceType.Customer).describe('客户'),
19
+ z.literal(ResourceType.Contact).describe('联系人'),
20
+ z.literal(ResourceType.Account).describe('账户'),
21
+ z.literal(ResourceType.Order).describe('订单'),
22
+ z.literal(ResourceType.Lead).describe('线索'),
23
+ z.literal(ResourceType.Opportunity).describe('商机'),
24
+ ])
25
+ .meta({ title: 'ResourceType', description: '资源类型', type: 'string' });
@@ -0,0 +1,42 @@
1
+ import { getGlobalStates } from '@wener/utils';
2
+ import type { JsonSchemaDef } from '../../jsonschema';
3
+ import { toJsonSchema, type SchemaOutput, type TypeSchema } from '../../schema';
4
+
5
+ const types = getGlobalStates('@wener/common/resource/schema/SchemaRegistry', () => new Map<string, JsonSchemaDef>());
6
+
7
+ export function get(name: string): JsonSchemaDef;
8
+ export function get<S extends TypeSchema>(schema: S): JsonSchemaDef<SchemaOutput<S>>;
9
+ export function get(needle: TypeSchema | string) {
10
+ let key = getKey(needle);
11
+ let found = types.get(key);
12
+ if (found) {
13
+ return found;
14
+ } else {
15
+ if (typeof needle !== 'string') {
16
+ return toJsonSchema(needle);
17
+ }
18
+ }
19
+ throw new Error(`Schema not found: ${key}`);
20
+ }
21
+
22
+ function getKey(s: TypeSchema | string) {
23
+ let key;
24
+ if (typeof s === 'string') {
25
+ key = s;
26
+ } else {
27
+ let js = toJsonSchema(s);
28
+ key = js.$id || js.title;
29
+ }
30
+ if (!key) {
31
+ throw new Error(`Schema must have $id or title`);
32
+ }
33
+ return key;
34
+ }
35
+
36
+ export function add(def: TypeSchema) {
37
+ types.set(getKey(def), toJsonSchema(def));
38
+ }
39
+
40
+ export function set(key: TypeSchema | string, def: TypeSchema) {
41
+ types.set(getKey(key), toJsonSchema(def));
42
+ }
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod/v4';
2
+ import type { EnumValues } from './types';
3
+
4
+ export const SexType = Object.freeze({
5
+ __proto__: null,
6
+ Male: 'Male',
7
+ Female: 'Female',
8
+ // Intersex
9
+ } as const);
10
+ export type SexType = EnumValues<typeof SexType>;
11
+ export const SexTypeSchema = z
12
+ .union([z.literal(SexType.Male).describe('男'), z.literal(SexType.Female).describe('女')])
13
+ .describe('性别');
@@ -0,0 +1,18 @@
1
+ import { describe, it } from 'vitest';
2
+ import { createSchemaData, toJsonSchema } from '../../schema';
3
+ import { renderJsonSchemaToMarkdownDoc } from '../../tools/renderJsonSchemaToMarkdownDoc';
4
+ import { AnyResourceSchema } from './AnyResourceSchema';
5
+
6
+ describe('schema', () => {
7
+ it('should be convert to jsonschema', () => {
8
+ console.log(renderJsonSchemaToMarkdownDoc(toJsonSchema(AnyResourceSchema)));
9
+ });
10
+
11
+ it('should create from schema', () => {
12
+ console.log(
13
+ createSchemaData(AnyResourceSchema, {
14
+ all: true,
15
+ }),
16
+ );
17
+ });
18
+ });
@@ -0,0 +1,105 @@
1
+ import { isValid } from 'date-fns';
2
+ import dayjs from 'dayjs';
3
+ import { z } from 'zod/v4';
4
+
5
+ const TypeIdSchema = z
6
+ .string()
7
+ .regex(/^[a-zA-Z0-9]+_[a-zA-Z0-9]+$/, {
8
+ error: 'ID格式错误',
9
+ })
10
+ .describe('ID');
11
+
12
+ /*
13
+ XXX-XXX-XXXX
14
+ National: (XXX) XXX-XXXX
15
+ Human: XXX.XXX.XXXX xXXX
16
+ International: +XX (XXX) XXX-XXXX
17
+
18
+ 中国
19
+ XXX XXXX XXXX
20
+ XXX-XXXX-XXXX
21
+ XXXXXXXXXXX
22
+ +86 XXX XXXX XXXX
23
+ +86 XXXXXXXXXXX
24
+
25
+ 0XX-XXXXXXXX
26
+ 0XXX-XXXXXXXX
27
+ (0XX) XXXXXXXX
28
+ 0XX XXXX XXXX
29
+ 0XXXXXXXX
30
+
31
+ https://uibakery.io/regex-library/phone-number
32
+ https://fakerjs.dev/api/phone
33
+ */
34
+
35
+ const PhoneNumberSchema = z
36
+ .string()
37
+ .trim()
38
+ .max(20)
39
+ .regex(/(^$)|(^[0-9]*$)/, {
40
+ error: '电话号码只能包含数字',
41
+ })
42
+ .meta({
43
+ format: 'phone',
44
+ });
45
+
46
+ function resourceIdOf(entity: string) {
47
+ return rz.resourceId.meta({ 'x-ref-entity': entity });
48
+ }
49
+
50
+ // allow empty string
51
+ const JsonDateSchema = z.coerce
52
+ .string()
53
+ .trim()
54
+ .overwrite((v) => {
55
+ if (v && !/^\d{4}-\d{2}-\d{2}$/.test(v)) {
56
+ let val = dayjs(v);
57
+ if (val.isValid()) {
58
+ return val.format('YYYY-MM-DD');
59
+ }
60
+ }
61
+ return v;
62
+ })
63
+ .regex(/(^$)|(^\d{4}-\d{2}-\d{2}$)/, { error: '错误的日期格式' })
64
+ .refine((value) => !value || isValid(new Date(value)), {
65
+ error: '错误的日期',
66
+ })
67
+ .nullish()
68
+ .overwrite((v) => v || undefined)
69
+ .meta({ format: 'date' });
70
+
71
+ const JsonDateTimeSchema = z.coerce.date().meta({ format: 'date-time', type: 'string' });
72
+
73
+ const LoginNameSchema = z
74
+ .string()
75
+ .trim()
76
+ .regex(/^[a-z0-9]{3,16}$/, { error: '登录名只能包含小写字母和数字,长度为3-16位' });
77
+
78
+ // maybe check valid cjk
79
+ const FriendlyNameSchema = z
80
+ .string()
81
+ .trim()
82
+ .max(50)
83
+ .refine((v) => !/\p{C}/u.test(v), { message: '包含无效字符' })
84
+ .describe('名称');
85
+
86
+ const PasswordSchema = z
87
+ .string()
88
+ .min(6, { error: '密码长度至少 6 位' })
89
+ .max(36, { error: '密码长度最多 36 位' })
90
+ .regex(/^\S*$/, { error: '密码不能包含空格' })
91
+ .describe('密码')
92
+ .meta({ sensitive: true });
93
+
94
+ export const rz = {
95
+ resourceIdOf: resourceIdOf,
96
+ date: JsonDateSchema,
97
+ dateTime: JsonDateTimeSchema,
98
+ resourceId: TypeIdSchema,
99
+ phoneNumber: PhoneNumberSchema,
100
+ loginName: LoginNameSchema,
101
+ password: PasswordSchema,
102
+ friendlyName: FriendlyNameSchema,
103
+ } as const;
104
+
105
+ export type EnumValues<T> = T[Exclude<keyof T, '__proto__'>];
@@ -0,0 +1,32 @@
1
+ import type {
2
+ TSchema,
3
+ StaticDecode as TypeBoxStaticDecode,
4
+ StaticEncode as TypeBoxStaticEncode,
5
+ } from '@sinclair/typebox';
6
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
7
+ import type { z } from 'zod/v4';
8
+ import type { JsonSchemaDef } from '../jsonschema';
9
+
10
+ export type TypeSchema<I = unknown, O = I> = TSchema | z.ZodSchema<O, I> | JsonSchemaDef | StandardSchemaV1<I, O>;
11
+
12
+ export type SchemaOutput<S extends TypeSchema> =
13
+ S extends StandardSchemaV1<infer I, infer O>
14
+ ? O
15
+ : S extends z.ZodSchema<infer O, infer I>
16
+ ? O
17
+ : S extends TSchema
18
+ ? TypeBoxStaticEncode<S>
19
+ : S extends JsonSchemaDef<infer I, infer O>
20
+ ? O
21
+ : never;
22
+
23
+ export type SchemaInput<S extends TypeSchema> =
24
+ S extends StandardSchemaV1<infer I, infer O>
25
+ ? I
26
+ : S extends z.ZodSchema<infer O, infer I>
27
+ ? I
28
+ : S extends TSchema
29
+ ? TypeBoxStaticDecode<S>
30
+ : S extends JsonSchemaDef<infer I, infer O>
31
+ ? I
32
+ : never;
@@ -0,0 +1,81 @@
1
+ import { match, P } from 'ts-pattern';
2
+ import type { JsonSchemaDef } from '../jsonschema';
3
+ import { toJsonSchema } from './toJsonSchema';
4
+ import type { SchemaOutput, TypeSchema } from './TypeSchema';
5
+
6
+ export function createSchemaData<S extends TypeSchema>(
7
+ ts: S,
8
+ options: CreateSchemaDataOptions = {},
9
+ ): Partial<SchemaOutput<S>> {
10
+ const schema = toJsonSchema(ts);
11
+ return createJsonSchemaData(schema, options);
12
+ }
13
+
14
+ type CreateSchemaDataOptions = Partial<CreateOptions> & {
15
+ all?: boolean;
16
+ };
17
+
18
+ function createJsonSchemaData(schema: JsonSchemaDef, options: CreateSchemaDataOptions): any {
19
+ let skip: CreateOptions['skip'] = (s, ctx) => Boolean(!ctx.required && s.nullable);
20
+ if (options.all) {
21
+ skip = () => false;
22
+ }
23
+ if (options.skip) {
24
+ skip = options.skip;
25
+ }
26
+ return _create(
27
+ schema,
28
+ {
29
+ skip,
30
+ },
31
+ { required: false },
32
+ );
33
+ }
34
+
35
+ type CreateOptions = {
36
+ skip: (schema: JsonSchemaDef, ctx: { required: boolean }) => boolean;
37
+ };
38
+
39
+ function _create(schema: JsonSchemaDef, options: CreateOptions, ctx: { required: boolean }): any {
40
+ const { skip } = options;
41
+ if (skip(schema, ctx)) {
42
+ return schema.default;
43
+ }
44
+ if (schema.default !== undefined) {
45
+ return schema.default;
46
+ }
47
+ return match(schema as JsonSchemaDef)
48
+ .returnType<any>()
49
+ .with({ default: P.select() }, (v) => v)
50
+ .with({ const: P.nonNullable }, (v) => v.const)
51
+ .with({ anyOf: P.nonNullable }, (schema) => {
52
+ return _create(schema.anyOf[0], options, { required: false });
53
+ })
54
+ .with({ oneOf: P.nonNullable }, (schema) => {
55
+ return _create(schema.oneOf[0], options, { required: false });
56
+ })
57
+ .with({ type: 'string' }, (schema) => '')
58
+ .with({ type: P.union('number', 'integer') }, (schema) => 0)
59
+ .with({ type: 'object' }, () => {
60
+ const out: Record<string, any> = {};
61
+
62
+ let required = schema.required || [];
63
+ for (const [k, v] of Object.entries(schema.properties || {}) as [string, JsonSchemaDef][]) {
64
+ const value = _create(v, options, {
65
+ required: required.includes(k),
66
+ });
67
+ if (value === undefined) {
68
+ continue;
69
+ }
70
+ out[k] = value;
71
+ }
72
+
73
+ return out;
74
+ })
75
+ .with({ type: 'null' }, () => null)
76
+ .with({ type: 'boolean' }, (schema) => false)
77
+ .with({ type: 'array' }, (schema) => [])
78
+ .otherwise(() => {
79
+ return undefined;
80
+ });
81
+ }
@@ -0,0 +1,37 @@
1
+ import { firstOfMaybeArray } from '@wener/utils';
2
+ import { toJsonSchema } from './toJsonSchema';
3
+ import type { TypeSchema } from './TypeSchema';
4
+
5
+ export function findJsonSchemaByPath(schema: TypeSchema, objectPath: string) {
6
+ schema = toJsonSchema(schema);
7
+ if (!objectPath || !schema) {
8
+ return undefined;
9
+ }
10
+
11
+ const segments = objectPath.split('.');
12
+ let currentSchema = schema;
13
+
14
+ for (const segment of segments) {
15
+ // 检查当前 schema 是否是对象类型且有 properties
16
+ if (
17
+ currentSchema
18
+ && typeof currentSchema === 'object'
19
+ && currentSchema.properties
20
+ && currentSchema.properties[segment]
21
+ ) {
22
+ currentSchema = currentSchema.properties[segment];
23
+ continue;
24
+ }
25
+
26
+ if (/^\d$/.test(segment) || segment === '[]') {
27
+ if (currentSchema.items) {
28
+ currentSchema = firstOfMaybeArray(currentSchema.items);
29
+ continue;
30
+ }
31
+ }
32
+
33
+ return undefined;
34
+ }
35
+
36
+ return currentSchema;
37
+ }
@@ -0,0 +1,21 @@
1
+ import type { JsonSchemaDef } from '../jsonschema';
2
+ import type { TypeSchema } from './TypeSchema';
3
+
4
+ type SchemaCache = {
5
+ jsonschema?: JsonSchemaDef;
6
+ options?: Array<{ value: string; label: string }>;
7
+ };
8
+ const _cache = new WeakMap<any, SchemaCache>();
9
+
10
+ export function getSchemaCache<K extends keyof SchemaCache>(
11
+ obj: TypeSchema,
12
+ key: K,
13
+ compute: () => NonNullable<SchemaCache[K]>,
14
+ ): NonNullable<SchemaCache[K]> {
15
+ let c = _cache.get(obj);
16
+ if (!c) {
17
+ c = {};
18
+ _cache.set(obj, c);
19
+ }
20
+ return (c[key] ??= compute());
21
+ }
@@ -0,0 +1,24 @@
1
+ import { deepFreeze } from '@wener/utils';
2
+ import { getSchemaCache } from './getSchemaCache';
3
+ import { toJsonSchema } from './toJsonSchema';
4
+ import type { TypeSchema } from './TypeSchema';
5
+
6
+ export function getSchemaOptions(s: TypeSchema): Array<{ value: string; label: string }> {
7
+ let js = toJsonSchema(s);
8
+ return getSchemaCache(s, 'options', () => {
9
+ let out =
10
+ (js.anyOf || js.oneOf)?.map((v) => {
11
+ let value = v.const;
12
+ return {
13
+ label: String(v.description || v.title || value),
14
+ value: value ? String(value) : '',
15
+ };
16
+ }) || [];
17
+ out = deepFreeze(out);
18
+ return out;
19
+ });
20
+ }
21
+
22
+ export function getSchemaOptionLabel(schema: TypeSchema, value: string | undefined | null): string | undefined {
23
+ return getSchemaOptions(schema).find((v) => v.value === value)?.label;
24
+ }
@@ -0,0 +1,6 @@
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
+ export { createSchemaData } from './createSchemaData';
@@ -0,0 +1,37 @@
1
+ import { inspect } from 'node:util';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { z } from 'zod/v4';
4
+ import { toJsonSchema } from './toJsonSchema';
5
+
6
+ describe('toJsonSchema', () => {
7
+ it('should handle discriminatedUnion', () => {
8
+ console.log(
9
+ inspect(
10
+ toJsonSchema(
11
+ z.discriminatedUnion('type', [
12
+ z.object({
13
+ type: z.literal('string'),
14
+ value: z.string(),
15
+ }),
16
+ z.object({
17
+ type: z.literal('number'),
18
+ value: z.number(),
19
+ }),
20
+ ]),
21
+ ),
22
+ {
23
+ depth: 10,
24
+ colors: true,
25
+ },
26
+ ),
27
+ );
28
+ });
29
+
30
+ it('should cache', () => {
31
+ let zs = z.object({
32
+ name: z.string(),
33
+ });
34
+
35
+ expect(toJsonSchema(zs)).toBe(toJsonSchema(zs));
36
+ });
37
+ });