@wener/common 1.0.5 → 2.0.2

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 (222) hide show
  1. package/lib/cn/ChineseResidentIdNo.js +41 -0
  2. package/lib/cn/ChineseResidentIdNo.mod.js +1 -0
  3. package/lib/cn/ChineseResidentIdNo.test.js +22 -0
  4. package/lib/cn/DivisionCode.js +214 -280
  5. package/lib/cn/DivisionCode.mod.js +1 -0
  6. package/lib/cn/DivisionCode.test.js +134 -0
  7. package/lib/cn/Mod11.js +86 -0
  8. package/lib/cn/Mod31.js +98 -0
  9. package/lib/cn/UnifiedSocialCreditCode.js +130 -109
  10. package/lib/cn/UnifiedSocialCreditCode.mod.js +1 -0
  11. package/lib/cn/UnifiedSocialCreditCode.test.js +16 -0
  12. package/lib/cn/index.js +1 -4
  13. package/lib/cn/mod.js +6 -0
  14. package/lib/cn/types.d.js +0 -2
  15. package/lib/consola/createStandardConsolaReporter.js +6 -6
  16. package/lib/consola/formatLogObject.js +147 -34
  17. package/lib/consola/index.js +0 -1
  18. package/lib/data/formatSort.js +5 -6
  19. package/lib/data/formatSort.test.js +34 -0
  20. package/lib/data/index.js +0 -1
  21. package/lib/data/maybeNumber.js +11 -5
  22. package/lib/data/parseSort.js +28 -22
  23. package/lib/data/parseSort.test.js +188 -0
  24. package/lib/data/resolvePagination.js +27 -16
  25. package/lib/data/resolvePagination.test.js +232 -0
  26. package/lib/data/types.d.js +0 -2
  27. package/lib/dayjs/dayjs.js +38 -0
  28. package/lib/dayjs/formatDuration.js +58 -0
  29. package/lib/dayjs/formatDuration.test.js +90 -0
  30. package/lib/dayjs/index.js +3 -0
  31. package/lib/dayjs/parseDuration.js +32 -0
  32. package/lib/decimal/index.js +1 -0
  33. package/lib/decimal/parseDecimal.js +13 -0
  34. package/lib/foundation/schema/SexType.js +14 -0
  35. package/lib/foundation/schema/index.js +1 -0
  36. package/lib/foundation/schema/parseSexType.js +18 -0
  37. package/lib/foundation/schema/types.js +5 -0
  38. package/lib/index.js +0 -1
  39. package/lib/jsonschema/JsonSchema.js +78 -52
  40. package/lib/jsonschema/JsonSchema.test.js +137 -0
  41. package/lib/jsonschema/index.js +0 -1
  42. package/lib/jsonschema/types.d.js +5 -3
  43. package/lib/meta/defineFileType.js +103 -20
  44. package/lib/meta/defineInit.js +250 -31
  45. package/lib/meta/defineMetadata.js +140 -24
  46. package/lib/meta/defineMetadata.test.js +13 -0
  47. package/lib/meta/index.js +0 -1
  48. package/lib/password/PHC.js +87 -63
  49. package/lib/password/PHC.test.js +539 -0
  50. package/lib/password/Password.js +295 -30
  51. package/lib/password/Password.test.js +362 -0
  52. package/lib/password/createArgon2PasswordAlgorithm.js +191 -35
  53. package/lib/password/createBase64PasswordAlgorithm.js +141 -8
  54. package/lib/password/createBcryptPasswordAlgorithm.js +168 -13
  55. package/lib/password/createPBKDF2PasswordAlgorithm.js +228 -46
  56. package/lib/password/createScryptPasswordAlgorithm.js +211 -55
  57. package/lib/password/index.js +0 -1
  58. package/lib/password/server/index.js +0 -1
  59. package/lib/resource/Identifiable.js +1 -0
  60. package/lib/resource/ListQuery.js +119 -0
  61. package/lib/resource/getTitleOfResource.js +10 -0
  62. package/lib/resource/index.js +2 -0
  63. package/lib/resource/schema/AnyResourceSchema.js +89 -0
  64. package/lib/resource/schema/BaseResourceSchema.js +29 -0
  65. package/lib/resource/schema/ResourceActionType.js +118 -0
  66. package/lib/resource/schema/ResourceStatus.js +93 -0
  67. package/lib/resource/schema/ResourceType.js +24 -0
  68. package/lib/resource/schema/index.js +5 -0
  69. package/lib/resource/schema/types.js +89 -0
  70. package/lib/resource/schema/types.test.js +14 -0
  71. package/lib/schema/SchemaRegistry.js +45 -0
  72. package/lib/schema/SchemaRegistry.mod.js +2 -0
  73. package/lib/schema/TypeSchema.d.js +1 -0
  74. package/lib/schema/createSchemaData.js +173 -0
  75. package/lib/schema/findJsonSchemaByPath.js +49 -0
  76. package/lib/schema/getSchemaCache.js +11 -0
  77. package/lib/schema/getSchemaOptions.js +24 -0
  78. package/lib/schema/index.js +6 -0
  79. package/lib/schema/toJsonSchema.js +441 -0
  80. package/lib/schema/toJsonSchema.test.js +27 -0
  81. package/lib/schema/validate.js +124 -0
  82. package/lib/tools/generateSchema.js +197 -39
  83. package/lib/tools/renderJsonSchemaToMarkdownDoc.js +143 -55
  84. package/lib/utils/getEstimateProcessTime.js +20 -0
  85. package/lib/utils/index.js +1 -0
  86. package/package.json +38 -17
  87. package/src/cn/ChineseResidentIdNo.mod.ts +7 -0
  88. package/src/cn/ChineseResidentIdNo.test.ts +18 -0
  89. package/src/cn/ChineseResidentIdNo.ts +66 -0
  90. package/src/cn/DivisionCode.mod.ts +7 -0
  91. package/src/cn/DivisionCode.test.ts +3 -13
  92. package/src/cn/DivisionCode.ts +132 -195
  93. package/src/cn/{Mod11Checksum.ts → Mod11.ts} +3 -1
  94. package/src/cn/{Mod31Checksum.ts → Mod31.ts} +2 -0
  95. package/src/cn/UnifiedSocialCreditCode.mod.ts +7 -0
  96. package/src/cn/UnifiedSocialCreditCode.test.ts +2 -2
  97. package/src/cn/UnifiedSocialCreditCode.ts +105 -125
  98. package/src/cn/__snapshots__/ChineseResidentIdNo.test.ts.snap +14 -0
  99. package/src/cn/__snapshots__/UnifiedSocialCreditCode.test.ts.snap +18 -12
  100. package/src/cn/index.ts +1 -3
  101. package/src/cn/mod.ts +3 -0
  102. package/src/consola/formatLogObject.ts +12 -4
  103. package/src/data/maybeNumber.ts +5 -1
  104. package/src/data/resolvePagination.test.ts +1 -1
  105. package/src/data/resolvePagination.ts +18 -7
  106. package/src/data/types.d.ts +12 -0
  107. package/src/dayjs/dayjs.ts +40 -0
  108. package/src/dayjs/formatDuration.test.ts +14 -0
  109. package/src/dayjs/formatDuration.ts +86 -0
  110. package/src/dayjs/index.ts +3 -0
  111. package/src/dayjs/parseDuration.ts +40 -0
  112. package/src/decimal/index.ts +1 -0
  113. package/src/decimal/parseDecimal.ts +16 -0
  114. package/src/foundation/schema/SexType.ts +21 -0
  115. package/src/foundation/schema/index.ts +1 -0
  116. package/src/foundation/schema/parseSexType.ts +19 -0
  117. package/src/foundation/schema/types.ts +8 -0
  118. package/src/jsonschema/JsonSchema.test.ts +17 -0
  119. package/src/jsonschema/JsonSchema.ts +2 -2
  120. package/src/jsonschema/types.d.ts +63 -12
  121. package/src/password/Password.ts +2 -2
  122. package/src/resource/Identifiable.ts +3 -0
  123. package/src/resource/ListQuery.ts +53 -0
  124. package/src/resource/getTitleOfResource.tsx +6 -0
  125. package/src/resource/index.ts +4 -0
  126. package/src/resource/schema/AnyResourceSchema.ts +113 -0
  127. package/src/resource/schema/BaseResourceSchema.ts +32 -0
  128. package/src/resource/schema/ResourceActionType.ts +123 -0
  129. package/src/resource/schema/ResourceStatus.ts +94 -0
  130. package/src/resource/schema/ResourceType.ts +25 -0
  131. package/src/resource/schema/index.ts +5 -0
  132. package/src/resource/schema/types.test.ts +18 -0
  133. package/src/resource/schema/types.ts +105 -0
  134. package/src/schema/SchemaRegistry.mod.ts +1 -0
  135. package/src/schema/SchemaRegistry.ts +46 -0
  136. package/src/schema/TypeSchema.d.ts +32 -0
  137. package/src/schema/createSchemaData.ts +81 -0
  138. package/src/schema/findJsonSchemaByPath.ts +37 -0
  139. package/src/schema/getSchemaCache.ts +21 -0
  140. package/src/schema/getSchemaOptions.ts +24 -0
  141. package/src/schema/index.ts +7 -0
  142. package/src/schema/toJsonSchema.test.ts +37 -0
  143. package/src/schema/toJsonSchema.ts +200 -0
  144. package/src/schema/validate.ts +135 -0
  145. package/src/tools/generateSchema.ts +28 -28
  146. package/src/utils/getEstimateProcessTime.ts +36 -0
  147. package/src/utils/index.ts +1 -0
  148. package/lib/cn/DivisionCode.js.map +0 -1
  149. package/lib/cn/Mod11Checksum.js +0 -42
  150. package/lib/cn/Mod11Checksum.js.map +0 -1
  151. package/lib/cn/Mod31Checksum.js +0 -48
  152. package/lib/cn/Mod31Checksum.js.map +0 -1
  153. package/lib/cn/ResidentIdentityCardNumber.js +0 -50
  154. package/lib/cn/ResidentIdentityCardNumber.js.map +0 -1
  155. package/lib/cn/UnifiedSocialCreditCode.js.map +0 -1
  156. package/lib/cn/formatDate.js +0 -15
  157. package/lib/cn/formatDate.js.map +0 -1
  158. package/lib/cn/index.js.map +0 -1
  159. package/lib/cn/parseSex.js +0 -22
  160. package/lib/cn/parseSex.js.map +0 -1
  161. package/lib/cn/types.d.js.map +0 -1
  162. package/lib/consola/createStandardConsolaReporter.js.map +0 -1
  163. package/lib/consola/formatLogObject.js.map +0 -1
  164. package/lib/consola/index.js.map +0 -1
  165. package/lib/data/formatSort.js.map +0 -1
  166. package/lib/data/index.js.map +0 -1
  167. package/lib/data/maybeNumber.js.map +0 -1
  168. package/lib/data/parseSort.js.map +0 -1
  169. package/lib/data/resolvePagination.js.map +0 -1
  170. package/lib/data/types.d.js.map +0 -1
  171. package/lib/index.js.map +0 -1
  172. package/lib/jsonschema/JsonSchema.js.map +0 -1
  173. package/lib/jsonschema/index.js.map +0 -1
  174. package/lib/jsonschema/types.d.js.map +0 -1
  175. package/lib/meta/defineFileType.js.map +0 -1
  176. package/lib/meta/defineInit.js.map +0 -1
  177. package/lib/meta/defineMetadata.js.map +0 -1
  178. package/lib/meta/index.js.map +0 -1
  179. package/lib/password/PHC.js.map +0 -1
  180. package/lib/password/Password.js.map +0 -1
  181. package/lib/password/createArgon2PasswordAlgorithm.js.map +0 -1
  182. package/lib/password/createBase64PasswordAlgorithm.js.map +0 -1
  183. package/lib/password/createBcryptPasswordAlgorithm.js.map +0 -1
  184. package/lib/password/createPBKDF2PasswordAlgorithm.js.map +0 -1
  185. package/lib/password/createScryptPasswordAlgorithm.js.map +0 -1
  186. package/lib/password/index.js.map +0 -1
  187. package/lib/password/server/index.js.map +0 -1
  188. package/lib/search/AdvanceSearch.js +0 -10
  189. package/lib/search/AdvanceSearch.js.map +0 -1
  190. package/lib/search/formatAdvanceSearch.js +0 -64
  191. package/lib/search/formatAdvanceSearch.js.map +0 -1
  192. package/lib/search/index.js +0 -2
  193. package/lib/search/index.js.map +0 -1
  194. package/lib/search/optimizeAdvanceSearch.js +0 -89
  195. package/lib/search/optimizeAdvanceSearch.js.map +0 -1
  196. package/lib/search/parseAdvanceSearch.js +0 -20
  197. package/lib/search/parseAdvanceSearch.js.map +0 -1
  198. package/lib/search/parser.d.js +0 -3
  199. package/lib/search/parser.d.js.map +0 -1
  200. package/lib/search/parser.js +0 -3065
  201. package/lib/search/parser.js.map +0 -1
  202. package/lib/search/types.d.js +0 -3
  203. package/lib/search/types.d.js.map +0 -1
  204. package/lib/tools/generateSchema.js.map +0 -1
  205. package/lib/tools/renderJsonSchemaToMarkdownDoc.js.map +0 -1
  206. package/src/cn/ResidentIdentityCardNumber.test.ts +0 -17
  207. package/src/cn/ResidentIdentityCardNumber.ts +0 -96
  208. package/src/cn/__snapshots__/ResidentIdentityCardNumber.test.ts.snap +0 -15
  209. package/src/cn/formatDate.ts +0 -12
  210. package/src/cn/parseSex.ts +0 -13
  211. package/src/search/AdvanceSearch.test.ts +0 -149
  212. package/src/search/AdvanceSearch.ts +0 -14
  213. package/src/search/Makefile +0 -2
  214. package/src/search/__snapshots__/AdvanceSearch.test.ts.snap +0 -675
  215. package/src/search/formatAdvanceSearch.ts +0 -52
  216. package/src/search/index.ts +0 -1
  217. package/src/search/optimizeAdvanceSearch.ts +0 -77
  218. package/src/search/parseAdvanceSearch.ts +0 -23
  219. package/src/search/parser.d.ts +0 -8
  220. package/src/search/parser.js +0 -2794
  221. package/src/search/parser.peggy +0 -237
  222. package/src/search/types.d.ts +0 -45
@@ -0,0 +1,66 @@
1
+ import { z } from 'zod/v4';
2
+ import { SexType, SexTypeSchema } from '../foundation/schema';
3
+ import { Mod11 } from './Mod11';
4
+
5
+ export const ChineseResidentIdNoRegex =
6
+ /^(?<division>[1-9]\d{5})(?<year>(18|19|20)\d{2})(?<month>0[1-9]|1[0-2])(?<day>0[1-9]|[12]\d|3[01])(?<sequence>\d{3})(?<checkDigit>[0-9Xx])$/;
7
+
8
+ export type ParsedChineseResidentIdNo = z.infer<typeof ParsedChineseResidentIdNoSchema>;
9
+ export const ParsedChineseResidentIdNoSchema = z
10
+ .object({
11
+ raw: z.string().regex(ChineseResidentIdNoRegex, '无效的18位身份证号码格式').describe('身份证号码'),
12
+ addressCode: z.string().length(6).describe('地址码 '),
13
+ birthDate: z.iso.date().describe('出生日期'),
14
+ sequence: z.int().max(999).min(0).describe('顺序码'),
15
+ checkDigit: z.int().min(0).max(10).describe('校验码'),
16
+ sex: SexTypeSchema.describe('性别'),
17
+ age: z.number().optional(),
18
+ valid: z.boolean().optional().describe('是否有效'),
19
+ })
20
+ .describe('居民身份证号码解析内容');
21
+
22
+ export function parseChineseResidentIdNo(idNo: string): ParsedChineseResidentIdNo | undefined {
23
+ const reg = ChineseResidentIdNoRegex;
24
+ const match = idNo.match(reg);
25
+ if (!match || !match.groups) {
26
+ return undefined;
27
+ }
28
+ const { division, year, month, day, sequence, checkDigit } = match.groups;
29
+ let seq = parseInt(sequence, 10);
30
+ return {
31
+ raw: idNo,
32
+ addressCode: division,
33
+ birthDate: `${year}-${month}-${day}`,
34
+ sequence: seq,
35
+ checkDigit: checkDigit.toUpperCase() === 'X' ? 10 : parseInt(checkDigit),
36
+ sex: seq % 2 === 0 ? SexType.Male : SexType.Female,
37
+ age: new Date().getFullYear() - parseInt(year, 10),
38
+ valid: Mod11.validate(idNo),
39
+ };
40
+ }
41
+
42
+ export function formatChineseResidentIdNo({
43
+ addressCode,
44
+ birthDate,
45
+ sequence,
46
+ checkDigit,
47
+ }: {
48
+ addressCode: string;
49
+ birthDate: string | Date;
50
+ sequence: number | string;
51
+ checkDigit?: string | number;
52
+ }): string {
53
+ const date =
54
+ typeof birthDate === 'string'
55
+ ? birthDate.replace(/-/g, '')
56
+ : `${birthDate.getFullYear()}${String(birthDate.getMonth() + 1).padStart(2, '0')}${String(birthDate.getDate()).padStart(2, '0')}`;
57
+ const seq = String(sequence).padStart(3, '0');
58
+ const major = `${addressCode}${date}${seq}`;
59
+ const check =
60
+ typeof checkDigit === 'number'
61
+ ? checkDigit === 10
62
+ ? 'X'
63
+ : String(checkDigit)
64
+ : checkDigit?.toUpperCase() || Mod11.compute(major);
65
+ return `${major}${check}`;
66
+ }
@@ -0,0 +1,7 @@
1
+ export {
2
+ DivisionCodeRegex as regex,
3
+ type ParsedDivisionCode as Result,
4
+ ParsedDivisionCodeSchema as ResultSchema,
5
+ parseDivisionCode as parse,
6
+ formatDivisionCode as format,
7
+ } from './DivisionCode';
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { DivisionCode } from './DivisionCode';
2
+ import { DivisionCode } from './mod';
3
3
 
4
4
  describe('DivisionCode', () => {
5
5
  it('should parse', () => {
@@ -7,27 +7,17 @@ describe('DivisionCode', () => {
7
7
  [
8
8
  '441900003001',
9
9
  {
10
- province: '44',
11
- city: '19',
12
- county: '00',
13
- town: '003',
14
- village: '001',
15
10
  codes: ['44', '19', '00', '003', '001'],
16
11
  },
17
12
  ],
18
13
  [
19
14
  441900003001,
20
15
  {
21
- province: '44',
22
- city: '19',
23
- county: '00',
24
- town: '003',
25
- village: '001',
26
16
  codes: ['44', '19', '00', '003', '001'],
27
17
  },
28
18
  ],
29
- [441900, { province: '44', city: '19', county: '00' }],
30
- ['31', { province: '31' }],
19
+ [441900, { codes: ['44', '19', '00'] }],
20
+ ['31', { codes: ['31'] }],
31
21
  ['4', undefined],
32
22
  ['', undefined],
33
23
  [null, undefined],
@@ -1,209 +1,146 @@
1
- const DivisionCodeLevels: Array<{ level: number; code: string; length: number; size: number; label: string }> = [
2
- { level: 1, code: 'Province', length: 2, size: 2, label: '' },
3
- { level: 2, code: 'City', length: 4, size: 2, label: '市' },
4
- { level: 3, code: 'County', length: 6, size: 2, label: '区县' },
5
- { level: 4, code: 'Town', length: 9, size: 3, label: '乡镇' },
6
- { level: 5, code: 'Village', length: 12, size: 3, label: '村' },
7
- ] as const;
8
-
9
- // String(Number.MAX_SAFE_INTEGER).length=16
10
- // 12 is safe int
1
+ import z from 'zod/v4';
2
+ import type { EnumValues } from '../resource/schema';
3
+
4
+ export const DivisionLevel = Object.freeze({
5
+ __proto__: null,
6
+ Province: 'Province',
7
+ City: 'City',
8
+ County: 'County',
9
+ Town: 'Town',
10
+ Village: 'Village',
11
+ });
12
+ const DivisionLevels = [
13
+ DivisionLevel.Province,
14
+ DivisionLevel.City,
15
+ DivisionLevel.County,
16
+ DivisionLevel.Town, // 3
17
+ DivisionLevel.Village, // 3
18
+ ];
19
+ export type DivisionLevel = EnumValues<typeof DivisionLevel>;
20
+ export const DivisionLevelSchema = z
21
+ .union([
22
+ z.literal(DivisionLevel.Province).describe('省级').meta({ ordinal: 1 }),
23
+ z.literal(DivisionLevel.City).describe('地级').meta({ ordinal: 2 }),
24
+ z.literal(DivisionLevel.County).describe('县级').meta({ ordinal: 3 }),
25
+ z.literal(DivisionLevel.Town).describe('乡镇级').meta({ ordinal: 4 }),
26
+ z.literal(DivisionLevel.Village).describe('村级').meta({ ordinal: 5 }),
27
+ ])
28
+ .describe('行政区划级别');
29
+
30
+ export type ParsedDivisionCode = z.infer<typeof ParsedDivisionCodeSchema>;
31
+ export const ParsedDivisionCodeSchema = z.object({
32
+ code: z.string().describe('行政区划代码'),
33
+ name: z.string().describe('行政区划名称'),
34
+ level: DivisionLevelSchema,
35
+ codes: z.string().array(),
36
+ names: z.string().array(),
37
+ latitude: z.number().optional().describe('纬度'),
38
+ longitude: z.number().optional().describe('经度'),
39
+ });
40
+
41
+ interface CodeName {
42
+ value: string;
43
+ name: string;
44
+ children?: Array<CodeName>;
45
+ }
11
46
 
12
- /**
13
- * Codes for the administrative divisions of the People's Republic of China
14
- *
15
- * @see https://zh.wikipedia.org/wiki/GB/T_2260 中华人民共和国行政区划代码
16
- */
17
- export namespace DivisionCode {
18
- enum DivisionCodeLevel {
19
- Province = 1,
20
- City = 2,
21
- County = 3,
22
- Town = 4,
23
- Village = 5,
47
+ export const DivisionCodeRegex =
48
+ /^(?<province>\d{2})(?<city>\d{2})?(?<county>\d{2})?(?<town>\d{3})?(?<village>\d{3})?$/;
49
+
50
+ const CodeNames: CodeName[] = [
51
+ { value: '11', name: '北京市' },
52
+ { value: '12', name: '天津市' },
53
+ { value: '13', name: '河北省' },
54
+ { value: '14', name: '山西省' },
55
+ { value: '15', name: '内蒙古自治区' },
56
+ { value: '21', name: '辽宁省' },
57
+ { value: '22', name: '吉林省' },
58
+ { value: '23', name: '黑龙江省' },
59
+ { value: '31', name: '上海市' },
60
+ { value: '32', name: '江苏省' },
61
+ { value: '33', name: '浙江省' },
62
+ { value: '34', name: '安徽省' },
63
+ { value: '35', name: '福建省' },
64
+ { value: '36', name: '江西省' },
65
+ { value: '37', name: '山东省' },
66
+ { value: '41', name: '河南省' },
67
+ { value: '42', name: '湖北省' },
68
+ { value: '43', name: '湖南省' },
69
+ { value: '44', name: '广东省' },
70
+ { value: '45', name: '广西壮族自治区' },
71
+ { value: '46', name: '海南省' },
72
+ { value: '50', name: '重庆市' },
73
+ { value: '51', name: '四川省' },
74
+ { value: '52', name: '贵州省' },
75
+ { value: '53', name: '云南省' },
76
+ { value: '54', name: '西藏自治区' },
77
+ { value: '61', name: '陕西省' },
78
+ { value: '62', name: '甘肃省' },
79
+ { value: '63', name: '青海省' },
80
+ { value: '64', name: '宁夏回族自治区' },
81
+ { value: '65', name: '新疆维吾尔自治区' },
82
+ { value: '71', name: '台湾省' },
83
+ { value: '81', name: '香港特别行政区' },
84
+ { value: '82', name: '澳门特别行政区' },
85
+ // 9 国外
86
+ ];
87
+
88
+ export function parseDivisionCode(code: string): ParsedDivisionCode | undefined {
89
+ const match = DivisionCodeRegex.exec(code);
90
+ if (!match) {
91
+ return undefined;
92
+ }
93
+ const { province, city, county, town, village } = match.groups ?? {};
94
+ if (!province) {
95
+ return undefined;
24
96
  }
25
97
 
26
- export const levels = DivisionCodeLevels;
27
-
28
- export const regex = /^(?<province>\d{2})(?<city>\d{2})?(?<county>\d{2})?(?<town>\d{3})?(?<village>\d{3})?$/;
29
-
30
- const root: CodeValue[] = [
31
- { value: '11', label: '北京市' },
32
- { value: '12', label: '天津市' },
33
- { value: '13', label: '河北省' },
34
- { value: '14', label: '山西省' },
35
- { value: '15', label: '内蒙古自治区' },
36
- { value: '21', label: '辽宁省' },
37
- { value: '22', label: '吉林省' },
38
- { value: '23', label: '黑龙江省' },
39
- { value: '31', label: '上海市' },
40
- { value: '32', label: '江苏省' },
41
- { value: '33', label: '浙江省' },
42
- { value: '34', label: '安徽省' },
43
- { value: '35', label: '福建省' },
44
- { value: '36', label: '江西省' },
45
- { value: '37', label: '山东省' },
46
- { value: '41', label: '河南省' },
47
- { value: '42', label: '湖北省' },
48
- { value: '43', label: '湖南省' },
49
- { value: '44', label: '广东省' },
50
- { value: '45', label: '广西壮族自治区' },
51
- { value: '46', label: '海南省' },
52
- { value: '50', label: '重庆市' },
53
- { value: '51', label: '四川省' },
54
- { value: '52', label: '贵州省' },
55
- { value: '53', label: '云南省' },
56
- { value: '54', label: '西藏自治区' },
57
- { value: '61', label: '陕西省' },
58
- { value: '62', label: '甘肃省' },
59
- { value: '63', label: '青海省' },
60
- { value: '64', label: '宁夏回族自治区' },
61
- { value: '65', label: '新疆维吾尔自治区' },
62
- { value: '71', label: '台湾省' },
63
- { value: '81', label: '香港特别行政区' },
64
- { value: '82', label: '澳门特别行政区' },
65
- // 9 国外
66
- ];
67
-
68
- export type ParsedCode = {
69
- province: string;
70
- city?: string;
71
- county?: string;
72
- town?: string;
73
- village?: string;
74
- codes: string[];
75
- level: DivisionCodeLevel;
76
- labels: string[];
77
- };
78
-
79
- export function parse(code: string | undefined | null | number): ParsedCode | undefined {
80
- if (!code) return;
81
- code = String(code);
82
- const match = regex.exec(code);
83
- if (!match) return;
84
- const { province, city, county, town, village } = match.groups ?? {};
85
- if (!province) return;
86
-
87
- let codes = [province, city, county, town, village].filter(Boolean);
88
- return { province, city, county, town, village, codes: codes, level: codes.length as DivisionCodeLevel };
98
+ const codes = [province, city, county, town, village].filter(Boolean);
99
+ const names: string[] = [];
100
+ {
101
+ let name = CodeNames.find((cn) => cn.value === province);
102
+ if (name) {
103
+ names.push(name.name);
104
+ }
89
105
  }
106
+ let level: DivisionLevel = DivisionLevels[codes.length - 1];
107
+ return {
108
+ code,
109
+ name: names.join(''),
110
+ level,
111
+ codes,
112
+ names,
113
+ };
114
+ }
90
115
 
91
- export function format({
92
- province,
93
- city,
94
- county,
95
- town,
96
- village,
97
- }: {
98
- province: string | number;
99
- city?: string | number;
100
- county?: string | number;
101
- town?: string | number;
102
- village?: string | number;
103
- }): string {
104
- const codes: string[] = [];
116
+ export function formatDivisionCode({
117
+ province,
118
+ city,
119
+ county,
120
+ town,
121
+ village,
122
+ codes = [],
123
+ }: {
124
+ province?: string | number;
125
+ city?: string | number;
126
+ county?: string | number;
127
+ town?: string | number;
128
+ village?: string | number;
129
+ codes?: string[];
130
+ }): string {
131
+ if (!codes.length) {
105
132
  for (let i = 0; i < [province, city, county, town, village].length; i++) {
106
133
  let x = [province, city, county, town, village][i];
107
134
  if (x === undefined || x === null || x === '') {
108
135
  break;
109
136
  }
110
- let len = levels[i].size;
111
- codes.push(String(x).padStart(len, '0').slice(0, len));
112
- }
113
- return codes.join('');
114
- }
115
-
116
- // export function random(level: DivisionCodeLevel = 'County'): string {
117
- // const l = DivisionCodeLevels.find((v) => v.code === level) || DivisionCodeLevels[2];
118
- // const l1 = randomPick(provinces);
119
- // if (l.level === 1) {
120
- // return String(l1[0]);
121
- // }
122
- // return l1 + String(Math.floor(Math.random() * parseFloat(`1e${l.length - 2}`) - 1));
123
- // }
124
- }
125
-
126
- interface DivisionTreeNode {
127
- sub: string; // sub code
128
- children?: Record<string, DivisionTreeNode>;
129
-
130
- code: string; // full code
131
- name?: string; // name of division
132
- }
133
-
134
- // export type DivisionCodeLevel = 'Village' | 'Town' | 'County' | 'City' | 'Province';
135
-
136
- // export interface ParsedDivisionCode {
137
- // level: DivisionCodeLevel;
138
- // code: string;
139
- // name?: string;
140
- // fullName?: string;
141
- // names: string[];
142
- // // 村级(村委会、居委会)
143
- // // 12 位
144
- // village?: CodeName;
145
- // // 乡级(乡镇、街道)
146
- // // 9 位
147
- // town?: CodeName;
148
- // // 县级(区县)
149
- // // 6 位 - 常用 - 2985 个
150
- // county?: CodeName;
151
- // // 地级(城市)
152
- // // 4 位 - 343 个
153
- // city?: CodeName;
154
- // // 省级(省份、直辖市、自治区)
155
- // // 2 位 - 32 个
156
- // province: CodeName;
157
- //
158
- // children?: Array<{ code: string; name?: string }>;
159
- // }
160
-
161
- // export interface CodeName {
162
- // code: string;
163
- // name: string;
164
- // }
165
-
166
- // export function getSimpleProvinceLabel(value: string) {
167
- // if (!value) {
168
- // return;
169
- // }
170
- // let label = value;
171
- // if (/[0-9]/.test(label)) {
172
- // label = label.slice(0, 2);
173
- // label = options.find((v) => v.value === label)?.label || label;
174
- // }
175
- // return label.replace(/省|市|(回族|维吾尔|壮族)?自治区|特别行政区$/, '');
176
- // }
177
-
178
- export function randomPick<T>(s: T[]) {
179
- return s[Math.floor(Math.random() * s.length)];
180
- }
181
-
182
- function lookup(opts: { values: string[]; root: CodeValue[] }): { found: CodeValue[] } {
183
- const { values, root } = opts;
184
- const found: CodeValue[] = [];
185
- let currentLevel = root;
186
-
187
- for (const v of values) {
188
- const node = currentLevel.find((n) => n.value === v);
189
- if (!node) {
190
- break;
191
- }
192
-
193
- found.push(node);
194
-
195
- if (node.children) {
196
- currentLevel = node.children;
197
- } else {
198
- break;
137
+ let size = 2;
138
+ if (i > 2) {
139
+ size = 3;
140
+ }
141
+ codes.push(String(x).padStart(size, '0').slice(0, size));
199
142
  }
200
143
  }
201
144
 
202
- return { found };
203
- }
204
-
205
- interface CodeValue {
206
- value: string;
207
- label: string;
208
- children?: Array<CodeValue>;
145
+ return codes.join('');
209
146
  }
@@ -2,7 +2,7 @@
2
2
  * ISO 7064:1983, MOD 11-2.
3
3
  */
4
4
  export class Mod11Checksum {
5
- weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
5
+ protected weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
6
6
 
7
7
  validate(s: string) {
8
8
  return s.at(-1) === this.compute(s.slice(0, s.length - 1));
@@ -22,3 +22,5 @@ export class Mod11Checksum {
22
22
  }
23
23
  }
24
24
  }
25
+
26
+ export const Mod11 = new Mod11Checksum();
@@ -34,3 +34,5 @@ export class Mod31Checksum {
34
34
  return this.toChar(31 - (sum % 31));
35
35
  }
36
36
  }
37
+
38
+ export const Mod31 = new Mod31Checksum();
@@ -0,0 +1,7 @@
1
+ export {
2
+ type ParsedUnifiedSocialCreditCode as Result,
3
+ UnifiedSocialCreditCodeRegex as regex,
4
+ ParsedUnifiedSocialCreditCodeSchema as ResultSchema,
5
+ parseUnifiedSocialCreditCode as parse,
6
+ formatUnifiedSocialCreditCode as format,
7
+ } from './UnifiedSocialCreditCode';
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { UnifiedSocialCreditCode } from './UnifiedSocialCreditCode';
2
+ import { UnifiedSocialCreditCode } from './mod';
3
3
 
4
4
  describe('UnifiedSocialCreditCode', () => {
5
5
  it('should parse', () => {
@@ -9,7 +9,7 @@ describe('UnifiedSocialCreditCode', () => {
9
9
  '91330106MA2CFLDG4R',
10
10
  ]) {
11
11
  let out = UnifiedSocialCreditCode.parse(a);
12
- expect(UnifiedSocialCreditCode.format(out)).toBe(a);
12
+ expect(UnifiedSocialCreditCode.format(out!)).toBe(a);
13
13
  expect(out).toMatchSnapshot();
14
14
  }
15
15
  });