@planet-matrix/mobius-model 0.3.0 → 0.5.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +30 -1
  3. package/dist/index.js +4 -2
  4. package/dist/index.js.map +22 -4
  5. package/package.json +3 -3
  6. package/scripts/build.ts +4 -4
  7. package/src/basic/README.md +144 -0
  8. package/src/basic/array.ts +872 -0
  9. package/src/basic/bigint.ts +114 -0
  10. package/src/basic/boolean.ts +180 -0
  11. package/src/basic/enhance.ts +10 -0
  12. package/src/basic/error.ts +51 -0
  13. package/src/basic/function.ts +453 -0
  14. package/src/basic/helper.ts +276 -0
  15. package/src/basic/index.ts +17 -0
  16. package/src/basic/is.ts +320 -0
  17. package/src/basic/number.ts +178 -0
  18. package/src/basic/object.ts +140 -0
  19. package/src/basic/promise.ts +464 -0
  20. package/src/basic/regexp.ts +7 -0
  21. package/src/basic/stream.ts +140 -0
  22. package/src/basic/string.ts +308 -0
  23. package/src/basic/symbol.ts +164 -0
  24. package/src/basic/temporal.ts +224 -0
  25. package/src/encoding/README.md +105 -0
  26. package/src/encoding/base64.ts +98 -0
  27. package/src/encoding/index.ts +1 -0
  28. package/src/index.ts +4 -0
  29. package/src/random/README.md +109 -0
  30. package/src/random/index.ts +1 -0
  31. package/src/random/uuid.ts +103 -0
  32. package/src/type/README.md +330 -0
  33. package/src/type/array.ts +5 -0
  34. package/src/type/boolean.ts +471 -0
  35. package/src/type/class.ts +419 -0
  36. package/src/type/function.ts +1519 -0
  37. package/src/type/helper.ts +135 -0
  38. package/src/type/index.ts +14 -0
  39. package/src/type/intersection.ts +93 -0
  40. package/src/type/is.ts +247 -0
  41. package/src/type/iteration.ts +233 -0
  42. package/src/type/number.ts +732 -0
  43. package/src/type/object.ts +788 -0
  44. package/src/type/path.ts +73 -0
  45. package/src/type/string.ts +1004 -0
  46. package/src/type/tuple.ts +2424 -0
  47. package/src/type/union.ts +108 -0
  48. package/tests/unit/basic/array.spec.ts +290 -0
  49. package/tests/unit/basic/bigint.spec.ts +50 -0
  50. package/tests/unit/basic/boolean.spec.ts +74 -0
  51. package/tests/unit/basic/error.spec.ts +32 -0
  52. package/tests/unit/basic/function.spec.ts +175 -0
  53. package/tests/unit/basic/helper.spec.ts +118 -0
  54. package/tests/unit/basic/number.spec.ts +74 -0
  55. package/tests/unit/basic/object.spec.ts +46 -0
  56. package/tests/unit/basic/promise.spec.ts +232 -0
  57. package/tests/unit/basic/regexp.spec.ts +11 -0
  58. package/tests/unit/basic/stream.spec.ts +120 -0
  59. package/tests/unit/basic/string.spec.ts +74 -0
  60. package/tests/unit/basic/symbol.spec.ts +72 -0
  61. package/tests/unit/basic/temporal.spec.ts +78 -0
  62. package/tests/unit/encoding/base64.spec.ts +40 -0
  63. package/tests/unit/random/uuid.spec.ts +37 -0
  64. package/dist/index.d.ts +0 -2
  65. package/dist/index.d.ts.map +0 -1
  66. package/dist/reactor/index.d.ts +0 -3
  67. package/dist/reactor/index.d.ts.map +0 -1
  68. package/dist/reactor/reactor-core/flags.d.ts +0 -99
  69. package/dist/reactor/reactor-core/flags.d.ts.map +0 -1
  70. package/dist/reactor/reactor-core/index.d.ts +0 -4
  71. package/dist/reactor/reactor-core/index.d.ts.map +0 -1
  72. package/dist/reactor/reactor-core/primitive.d.ts +0 -276
  73. package/dist/reactor/reactor-core/primitive.d.ts.map +0 -1
  74. package/dist/reactor/reactor-core/reactive-system.d.ts +0 -241
  75. package/dist/reactor/reactor-core/reactive-system.d.ts.map +0 -1
  76. package/dist/reactor/reactor-operators/branch.d.ts +0 -19
  77. package/dist/reactor/reactor-operators/branch.d.ts.map +0 -1
  78. package/dist/reactor/reactor-operators/convert.d.ts +0 -30
  79. package/dist/reactor/reactor-operators/convert.d.ts.map +0 -1
  80. package/dist/reactor/reactor-operators/create.d.ts +0 -26
  81. package/dist/reactor/reactor-operators/create.d.ts.map +0 -1
  82. package/dist/reactor/reactor-operators/filter.d.ts +0 -269
  83. package/dist/reactor/reactor-operators/filter.d.ts.map +0 -1
  84. package/dist/reactor/reactor-operators/index.d.ts +0 -8
  85. package/dist/reactor/reactor-operators/index.d.ts.map +0 -1
  86. package/dist/reactor/reactor-operators/join.d.ts +0 -48
  87. package/dist/reactor/reactor-operators/join.d.ts.map +0 -1
  88. package/dist/reactor/reactor-operators/map.d.ts +0 -165
  89. package/dist/reactor/reactor-operators/map.d.ts.map +0 -1
  90. package/dist/reactor/reactor-operators/utility.d.ts +0 -48
  91. package/dist/reactor/reactor-operators/utility.d.ts.map +0 -1
@@ -0,0 +1,105 @@
1
+ # Encoding
2
+
3
+ Runtime utilities for encoding and decoding text. This module currently focuses on Base64 conversions with predictable UTF-8 behavior.
4
+
5
+ ## For Users
6
+
7
+ This module provides lightweight encoding helpers for common text <-> Base64 scenarios.
8
+
9
+ ### 1. Domain Areas
10
+
11
+ 1. Base64: Convert UTF-8 strings to Base64, decode Base64 back to UTF-8 strings, and validate Base64 input.
12
+
13
+ Current public exports:
14
+
15
+ - `isBase64(input: string): boolean`
16
+ - `assertBase64(input: string): void`
17
+ - `stringToBase64(input: string): string`
18
+ - `base64ToString(input: string): string`
19
+
20
+ ## For Contributors
21
+
22
+ This guide documents conventions and best practices for implementing encoding utilities in this module.
23
+
24
+ ### 1. Documentation and Comments
25
+
26
+ #### 1.1 JSDoc Comment Format
27
+
28
+ Every exported function should include JSDoc in this form:
29
+
30
+ ```typescript
31
+ /**
32
+ * Brief one-line description of what the function does.
33
+ *
34
+ * @example
35
+ * ```
36
+ * // Expect: "aGVsbG8="
37
+ * const example1 = stringToBase64("hello")
38
+ * // Expect: "hello"
39
+ * const example2 = base64ToString("aGVsbG8=")
40
+ * ```
41
+ */
42
+ export const stringToBase64 = (input: string): string => {
43
+ ...
44
+ }
45
+ ```
46
+
47
+ **Documentation Rules:**
48
+ - First line: Clear, concise description starting with a verb (Check, Get, Convert, etc.)
49
+ - Add a blank line after the description
50
+ - Use `@example` tag followed by triple backticks
51
+ - Include multiple cases showing different scenarios
52
+ - Use comment format: `// Expect: <result>`
53
+ - Assign example results to variables like `example1`, `example2` to keep examples readable
54
+ - Place `@see`(if has) after the `@example` block, separated by a blank line
55
+ - Prefer deterministic examples; avoid randomness or time-dependent output in docs
56
+ - If a function returns a non-scalar, show the expected shape or key properties
57
+
58
+ ### 2. Runtime Implementation Patterns
59
+
60
+ #### 2.1 Input and Output Rules
61
+
62
+ - Text conversion utilities should accept explicit `string` input.
63
+ - Behavior should be deterministic and side-effect free.
64
+ - Keep UTF-8 semantics explicit in implementation.
65
+
66
+ #### 2.2 Helper Placement
67
+
68
+ - Place local helper constants/functions immediately before the utility they support.
69
+ - Prefix non-exported helpers with `internal`.
70
+ - Never export internal helpers.
71
+
72
+ #### 2.3 Spacing
73
+
74
+ - Separate different utility functions with a single blank line.
75
+
76
+ ### 3. Naming Conventions
77
+
78
+ #### 3.1 Function Name Format
79
+
80
+ Use clear operation-oriented names in the `encoding` domain:
81
+
82
+ - `isBase64` for Base64 validation checks returning boolean
83
+ - `assertBase64` for Base64 validation that throws on malformed input
84
+ - `stringToBase64` for UTF-8 string to Base64 conversion
85
+ - `base64ToString` for Base64 to UTF-8 string conversion
86
+
87
+ Prefer names that encode both source and target representations.
88
+
89
+ ### 4. Export Strategy
90
+
91
+ - Export all public utilities from domain files.
92
+ - Re-export them through `index.ts`.
93
+ - Do not export internal helpers.
94
+
95
+ ### 5. Common Pitfalls to Avoid
96
+
97
+ 1. Do not assume all Base64 input is valid without documenting behavior.
98
+ 2. Do not mix encodings implicitly (keep UTF-8 explicit).
99
+ 3. Do not add environment-specific APIs unless compatibility is documented.
100
+ 4. Do not mutate shared state.
101
+
102
+ ### 6. Testing Requirements
103
+
104
+ - Write one test per function.
105
+ - If multiple cases are needed, include them within the same test.
@@ -0,0 +1,98 @@
1
+ const internalBase64Pattern = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/
2
+ const internalNormalizeBase64 = (input: string): string => {
3
+ return input.replaceAll(/\s+/g, "")
4
+ }
5
+ /**
6
+ * Check whether input is a valid Base64 string.
7
+ *
8
+ * @example
9
+ * ```
10
+ * // Expect: true
11
+ * const example1 = isBase64("aGVsbG8=")
12
+ * // Expect: false
13
+ * const example2 = isBase64("abc")
14
+ * ```
15
+ */
16
+ export const isBase64 = (input: string): boolean => {
17
+ const normalizedInput = internalNormalizeBase64(input)
18
+ return internalBase64Pattern.test(normalizedInput)
19
+ }
20
+
21
+ const internalAssertValidBase64 = (input: string): void => {
22
+ if (internalBase64Pattern.test(input) === false) {
23
+ throw new TypeError("Invalid Base64 input")
24
+ }
25
+ }
26
+ /**
27
+ * Assert input is a valid Base64 string.
28
+ *
29
+ * @throws {TypeError} when input is not valid Base64
30
+ */
31
+ export const assertBase64 = (input: string): void => {
32
+ const normalizedInput = internalNormalizeBase64(input)
33
+ internalAssertValidBase64(normalizedInput)
34
+ }
35
+
36
+ const internalStringToBase64ByBrowserApi = (input: string): string => {
37
+ const bytes = new TextEncoder().encode(input)
38
+ let binaryString = ""
39
+
40
+ bytes.forEach((byte) => {
41
+ binaryString = binaryString + String.fromCodePoint(byte)
42
+ })
43
+
44
+ return btoa(binaryString)
45
+ }
46
+ /**
47
+ * Convert a UTF-8 string into a Base64 string.
48
+ *
49
+ * @example
50
+ * ```
51
+ * // Expect: "aGVsbG8="
52
+ * const example1 = stringToBase64("hello")
53
+ * // Expect: "5L2g5aW9"
54
+ * const example2 = stringToBase64("你好")
55
+ * ```
56
+ */
57
+ export const stringToBase64 = (input: string): string => {
58
+ if (typeof Buffer !== "undefined") {
59
+ return Buffer.from(input, "utf8").toString("base64")
60
+ }
61
+
62
+ if (typeof btoa !== "undefined") {
63
+ return internalStringToBase64ByBrowserApi(input)
64
+ }
65
+
66
+ throw new Error("No Base64 runtime support found")
67
+ }
68
+
69
+ const internalBase64ToStringByBrowserApi = (input: string): string => {
70
+ const binaryString = atob(input)
71
+ const bytes = Uint8Array.from(binaryString, char => char.codePointAt(0) ?? 0)
72
+ return new TextDecoder().decode(bytes)
73
+ }
74
+ /**
75
+ * Convert a valid Base64 string into a UTF-8 string.
76
+ *
77
+ * @example
78
+ * ```
79
+ * // Expect: "hello"
80
+ * const example1 = base64ToString("aGVsbG8=")
81
+ * // Expect: "你好"
82
+ * const example2 = base64ToString("5L2g5aW9")
83
+ * ```
84
+ */
85
+ export const base64ToString = (input: string): string => {
86
+ const normalizedInput = internalNormalizeBase64(input)
87
+ internalAssertValidBase64(normalizedInput)
88
+
89
+ if (typeof Buffer !== "undefined") {
90
+ return Buffer.from(normalizedInput, "base64").toString("utf8")
91
+ }
92
+
93
+ if (typeof atob !== "undefined") {
94
+ return internalBase64ToStringByBrowserApi(normalizedInput)
95
+ }
96
+
97
+ throw new Error("No Base64 runtime support found")
98
+ }
@@ -0,0 +1 @@
1
+ export * from "./base64.ts"
package/src/index.ts CHANGED
@@ -1 +1,5 @@
1
+ export * as Basic from "./basic/index.ts"
2
+ export * as Type from "./type/index.ts"
1
3
  export * as Reactor from "./reactor/index.ts"
4
+ export * as Encoding from "./encoding/index.ts"
5
+ export * as Random from "./random/index.ts"
@@ -0,0 +1,109 @@
1
+ # Random
2
+
3
+ Runtime utilities for generating random-oriented values with cross-runtime compatibility. This module currently focuses on UUID generation.
4
+
5
+ ## For Users
6
+
7
+ This module provides lightweight helpers for random value generation scenarios.
8
+
9
+ ### 1. Domain Areas
10
+
11
+ 1. UUID: Generate RFC 4122 version-4 UUID strings with runtime-aware fallback behavior.
12
+
13
+ Current public exports:
14
+
15
+ - `isUuid(input: string): boolean`
16
+ - `assertUuid(input: string): void`
17
+ - `getUuidVersion(input: string): number`
18
+ - `generateUuid(): string`
19
+
20
+ ## For Contributors
21
+
22
+ This guide documents conventions and best practices for implementing random utilities in this module.
23
+
24
+ ### 1. Documentation and Comments
25
+
26
+ #### 1.1 JSDoc Comment Format
27
+
28
+ Every exported function should include JSDoc in this form:
29
+
30
+ ```typescript
31
+ /**
32
+ * Brief one-line description of what the function does.
33
+ *
34
+ * @example
35
+ * ```
36
+ * const example1 = generateUuid()
37
+ * // Expect: true
38
+ * const example2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(example1)
39
+ * ```
40
+ */
41
+ export const generateUuid = (): string => {
42
+ ...
43
+ }
44
+ ```
45
+
46
+ **Documentation Rules:**
47
+ - First line: Clear, concise description starting with a verb (Generate, Check, Convert, etc.)
48
+ - Add a blank line after the description
49
+ - Use `@example` tag followed by triple backticks
50
+ - Include multiple cases showing different scenarios
51
+ - Use comment format: `// Expect: <result>`
52
+ - Assign example results to variables like `example1`, `example2` to keep examples readable
53
+ - Place `@see`(if has) after the `@example` block, separated by a blank line
54
+ - Prefer deterministic examples; avoid asserting exact random outputs
55
+ - If a function returns a structured string, show expected format characteristics
56
+
57
+ ### 2. Runtime Implementation Patterns
58
+
59
+ #### 2.1 Compatibility First
60
+
61
+ - Prefer standard runtime APIs when available (for example, `crypto.randomUUID`).
62
+ - Keep fallback logic for environments where modern APIs are unavailable.
63
+
64
+ #### 2.2 Deterministic Interface
65
+
66
+ - Public API shape should remain deterministic even if output values are random.
67
+ - Return values should always conform to the documented output format.
68
+
69
+ #### 2.3 Helper Placement
70
+
71
+ - Place local helper constants/functions immediately before the utility they support.
72
+ - Prefix non-exported helpers with `internal`.
73
+ - Never export internal helpers.
74
+
75
+ #### 2.4 Spacing
76
+
77
+ - Separate different utility functions with a single blank line.
78
+
79
+ ### 3. Naming Conventions
80
+
81
+ #### 3.1 Function Name Format
82
+
83
+ Use clear operation-oriented names in the `random` domain:
84
+
85
+ - `isUuid` for UUID format validation checks
86
+ - `assertUuid` for UUID validation that throws on malformed input
87
+ - `getUuidVersion` for extracting UUID version numbers
88
+ - `generateUuid` for UUID creation helpers
89
+
90
+ Prefer names that clearly indicate output format and intent.
91
+
92
+ ### 4. Export Strategy
93
+
94
+ - Export all public utilities from domain files.
95
+ - Re-export them through `index.ts`.
96
+ - Do not export internal helpers.
97
+
98
+ ### 5. Common Pitfalls to Avoid
99
+
100
+ 1. Do not assume browser-only APIs are always available.
101
+ 2. Do not couple random utilities to a specific runtime unless documented.
102
+ 3. Do not assert exact random results in tests.
103
+ 4. Do not mutate shared/global state permanently.
104
+
105
+ ### 6. Testing Requirements
106
+
107
+ - Write one test per function.
108
+ - If multiple cases are needed, include them within the same test.
109
+ - For random outputs, validate shape/constraints instead of exact value.
@@ -0,0 +1 @@
1
+ export * from "./uuid.ts"
@@ -0,0 +1,103 @@
1
+
2
+ const internalUUID_REGEXP = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
3
+ /**
4
+ * Check whether input is a valid UUID string.
5
+ *
6
+ * @example
7
+ * ```
8
+ * // Expect: true
9
+ * const example1 = isUuid("550e8400-e29b-41d4-a716-446655440000")
10
+ * // Expect: false
11
+ * const example2 = isUuid("not-a-uuid")
12
+ * ```
13
+ */
14
+ export const isUuid = (input: string): boolean => {
15
+ return internalUUID_REGEXP.test(input)
16
+ }
17
+
18
+ /**
19
+ * Assert input is a valid UUID string.
20
+ *
21
+ * @example
22
+ * ```
23
+ * // Expect: no throw
24
+ * const example1 = assertUuid("550e8400-e29b-41d4-a716-446655440000")
25
+ * // Expect: throws TypeError
26
+ * const example2 = () => assertUuid("not-a-uuid")
27
+ * ```
28
+ *
29
+ * @throws {TypeError} when input is not a valid UUID
30
+ */
31
+ export const assertUuid = (input: string): void => {
32
+ if (isUuid(input) === false) {
33
+ throw new TypeError(`Expected a valid UUID string, got: ${input}`)
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Get the version number from a valid UUID string.
39
+ *
40
+ * @example
41
+ * ```
42
+ * // Expect: 4
43
+ * const example1 = getUuidVersion("550e8400-e29b-41d4-a716-446655440000")
44
+ * // Expect: 1
45
+ * const example2 = getUuidVersion("123e4567-e89b-12d3-a456-426614174000")
46
+ * ```
47
+ *
48
+ * @throws {TypeError} when input is not a valid UUID
49
+ */
50
+ export const getUuidVersion = (input: string): number => {
51
+ // 1) Ensure the input is a syntactically valid UUID string.
52
+ // If invalid, assertUuid throws TypeError and prevents unsafe parsing.
53
+ assertUuid(input)
54
+
55
+ // 2) Per UUID canonical format xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx,
56
+ // the version nibble is the first hex digit of the 3rd group.
57
+ // In a 36-char UUID string, that position is index 14.
58
+
59
+ // 3) Convert the single hex character (for example "4") to a base-10 number.
60
+ // parseInt("4", 16) -> 4, parseInt("a", 16) -> 10.
61
+ return Number.parseInt(input[14]!, 16)
62
+ }
63
+
64
+ /**
65
+ * Generate a RFC 4122 version-4 UUID string.
66
+ *
67
+ * @example
68
+ * ```
69
+ * const example1 = generateUuid()
70
+ * // Expect: true
71
+ * const example2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(example1)
72
+ * ```
73
+ */
74
+ export const generateUuid = (): string => {
75
+ if (typeof crypto === "object") {
76
+ if (typeof crypto.randomUUID === "function") {
77
+ return crypto.randomUUID()
78
+ }
79
+
80
+ if (typeof crypto.getRandomValues === "function" && typeof Uint8Array === "function") {
81
+ const buffer = new Uint8Array(16)
82
+ crypto.getRandomValues(buffer)
83
+
84
+ // Per RFC 4122, set bits for version and `clock_seq_hi_and_reserved`
85
+ buffer[6] = (buffer[6]! & 0x0F) | 0x40 // version 4
86
+ buffer[8] = (buffer[8]! & 0x3F) | 0x80 // variant 1
87
+
88
+ // Convert buffer to UUID string format
89
+ const hex = [...buffer].map(b => b.toString(16).padStart(2, "0")).join("")
90
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`
91
+ }
92
+ }
93
+
94
+ // Fallback for environments without crypto support
95
+ const fallbackUUID = (): string => {
96
+ const random = (a: number): string => {
97
+ return ((a ^ ((Math.random() * 16) >> (a / 4))) & 15).toString(16)
98
+ }
99
+ return "10000000-1000-4000-8000-100000000000".replaceAll(/[018]/g, (char: string) => random(Number(char)))
100
+ }
101
+
102
+ return fallbackUUID()
103
+ }