@sandlada/result 0.0.1-20260701.a → 0.0.1-20260701.b

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 (2) hide show
  1. package/README.md +89 -152
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,183 +1,120 @@
1
- # @sandlada/jss
1
+ # @sandlada/result
2
2
 
3
- 一個簡單的 CSS-in-JS 函式庫,提供兩類工具來管理 CSS 自訂屬性(變數):
3
+ ![NPM Downloads](https://img.shields.io/npm/d18m/@sandlada/result?label=NPM%20Downloads&labelColor=%2300531f&color=%23a3f5aa)
4
+ ![NPM Version](https://img.shields.io/npm/v/%40sandlada%2Fresult?label=NPM%20Version&labelColor=%2300531f&color=%23a3f5aa)
5
+ ![GitHub License](https://img.shields.io/github/license/sandlada/result?label=License&labelColor=%2300531f&color=%23a3f5aa)
4
6
 
5
- - **define 系列**產生 CSS 宣告(`--name: value`),用於輸出到樣式表
6
- - **use 系列** — 產生 `var()` 引用(`var(--name, fallback)`),用於組合進其他宣告中
7
+ `@sandlada/result` is a TypeScript library implementing the **Result pattern**a type-safe, exception-free approach to error handling. It makes error flows explicit in the type system so you never wonder whether a function can fail.
7
8
 
8
- 完整文件請參閱 [docs/README.md](./docs/README.md)。
9
+ Unlike traditional Result libraries that hardcode a single error type, `@sandlada/result` is **fully generic**: you bring your own error shapes (discriminated unions, classes, or plain objects).
9
10
 
10
- ## 安裝
11
+ ## :zap: Highlights
11
12
 
12
- ```bash
13
- npm install @sandlada/jss
14
- ```
15
-
16
- 專案使用 TypeScript 6 + ESM,匯入即可獲得完整的型別推斷。
17
-
18
- ---
19
-
20
- ## define 系列 — 產生 CSS 宣告
21
-
22
- | 函式 | 說明 | 文件 |
23
- | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
24
- | `defineVars(name, value)` | 基本變數定義,回傳字串陣列 | [docs/define-vars.md](./docs/define-vars.md) |
25
- | `defineLogicalBorderRadiusVars(base, value, options?)` | 展開為四個邏輯角(`start-start` / `start-end` / `end-start` / `end-end`),回傳陣列,支援 `{ semi?, prefix? }` | [docs/define-logical-border-radius-vars.md](./docs/define-logical-border-radius-vars.md) |
26
- | `defineLogicalBorderRadiusVarsRecord(base, value)` | 同上,但回傳 Record 物件 | [docs/define-logical-border-radius-vars-record.md](./docs/define-logical-border-radius-vars-record.md) |
27
- | `defineTokenRefsRecord(tokens, options?)` | 將設計 Token 綁定為內部變數(`--_key: var(--key, value)`),支援形狀屬性展開與 `{ prefix? }` | [docs/define-token-refs-record.md](./docs/define-token-refs-record.md) |
28
- | `defineOverrides(source, overrides)(prefix?)` | 型別安全的樣式覆蓋輔助,Curried API,可傳入 `null` 跳過型別約束 | [docs/define-overrides.md](./docs/define-overrides.md) |
29
-
30
- ```ts
31
- import { defineVars } from '@sandlada/jss'
32
-
33
- // ['--color: red']
34
- defineVars('color', 'red')
13
+ - Fully generic `TError` — define your own error types
14
+ - Zero dependencies
15
+ - ESM-only, strict TypeScript
16
+ - Inspired by the C# Result pattern
35
17
 
36
- // ['--color: red', '--bg-color: blue']
37
- defineVars({ color: 'red', 'bg-color': 'blue' })
18
+ ## :eyes: Installation
38
19
 
39
- // 第三個參數 true 加上分號尾綴
40
- defineVars('color', 'red', true) // ['--color: red;']
41
- ```
42
-
43
- ```ts
44
- import { defineTokenRefsRecord } from '@sandlada/jss'
45
-
46
- const AppTokens = {
47
- 'button-text-color': 'red',
48
- 'button-bg-color': 'white',
49
- 'button-shape': 'var(--md-sys-shape-corner-full, 9999px)',
50
- } as const
51
-
52
- // 將設計 Token 綁定為內部變數:
53
- // { '--_button-text-color': 'var(--button-text-color, red)', ... }
54
- defineTokenRefsRecord(AppTokens)
55
-
56
- // 使用 prefix 為所有 token 加上前綴:
57
- defineTokenRefsRecord(AppTokens, { prefix: '--md-badge' })
58
- // { '--_button-text-color': 'var(--md-badge-button-text-color, red)', ... }
59
-
60
- // 展開形狀屬性為四個邏輯角:
61
- defineTokenRefsRecord(AppTokens, { expandShapes: ['button-shape'] })
62
- // {
63
- // '--_button-text-color': 'var(--button-text-color, red)',
64
- // '--_button-shape-start-start': 'var(--button-shape-start-start, var(--md-sys-shape-corner-full, 9999px))',
65
- // '--_button-shape-start-end': 'var(--button-shape-start-end, ...)',
66
- // '--_button-shape-end-start': 'var(--button-shape-end-start, ...)',
67
- // '--_button-shape-end-end': 'var(--button-shape-end-end, ...)',
68
- // }
69
-
70
- // 加入基底變數作為中繼備援(兩層 var() 遞迴):
71
- defineTokenRefsRecord(AppTokens, { expandShapes: ['button-shape'], useBaseFallback: true })
72
- // {
73
- // '--_button-shape-start-start': 'var(--button-shape-start-start, var(--button-shape, var(--md-sys-shape-corner-full, 9999px)))',
74
- // ...
75
- // }
20
+ ```bash
21
+ npm i @sandlada/result
76
22
  ```
77
23
 
78
- ---
24
+ > **ESM only.** This package cannot be used with `require()`. Your project must use ESM (`import`) or dynamic `import()`.
79
25
 
80
- ## defineOverrides 型別安全的樣式覆蓋
26
+ ## :ship: Quick Start
81
27
 
82
28
  ```ts
83
- import { defineOverrides } from '@sandlada/jss'
29
+ import { Result, type IResultOfT } from '@sandlada/result';
30
+
31
+ // Define your error type (discriminated union recommended)
32
+ type AppError =
33
+ | { kind: 'NotFound'; id: string }
34
+ | { kind: 'Validation'; fields: Record<string, string> };
35
+
36
+ function getUser(id: string): IResultOfT<User, AppError> {
37
+ if (!id) {
38
+ return Result.Failure<User, AppError>({
39
+ kind: 'Validation',
40
+ fields: { id: 'Required' },
41
+ });
42
+ }
43
+ const user = db.find(id);
44
+ if (!user) {
45
+ return Result.Failure<User, AppError>({
46
+ kind: 'NotFound',
47
+ id,
48
+ });
49
+ }
50
+ return Result.Success(user);
51
+ }
84
52
 
85
- const FocusRing = {
86
- 'outline-color': 'red',
87
- 'outline-width': '2px',
88
- } as const
53
+ // Consume with type narrowing
54
+ const result = getUser('42');
55
+ if (result.isSuccess) {
56
+ console.log(result.value.name); // ✅ User
57
+ } else {
58
+ switch (result.error.kind) {
59
+ case 'NotFound': /* ... */ break;
60
+ case 'Validation': /* ... */ break;
61
+ }
62
+ }
63
+ ```
89
64
 
90
- // 型別安全模式:從 source 推導鍵值約束,所有鍵皆為可選
91
- // { 'outline-color': 'blue' }
92
- defineOverrides(FocusRing, { 'outline-color': 'blue' })()
65
+ ## :ledger: Core Types
93
66
 
94
- // 套用 CSS 變數前綴
95
- // { '--my-comp-outline-color': 'blue' }
96
- defineOverrides(FocusRing, { 'outline-color': 'blue' })('--my-comp')
67
+ | Export | Kind | Signature | Description |
68
+ | ------------ | --------- | ------------------------------------ | -------------------------------- |
69
+ | `IResult` | interface | `IResult<TError = Error>` | Base result contract (no value) |
70
+ | `IResultOfT` | interface | `IResultOfT<TValue, TError = Error>` | Result carrying a success value |
71
+ | `Result` | class | `Result<TError = Error>` | Base class with static factories |
72
+ | `ResultOfT` | class | `ResultOfT<TValue, TError = Error>` | Generic result class with value |
97
73
 
98
- // 部分覆蓋或空物件皆可
99
- defineOverrides(FocusRing, {})()
74
+ ### Factory Methods
100
75
 
101
- // 無型別約束模式:source 傳入 null
102
- defineOverrides(null, { 'outline-color': 'blue' })()
76
+ All factories live on `Result`:
103
77
 
104
- // 實際使用:覆蓋共享元件樣式
105
- const CompB = {
106
- 'bg-color': 'blue',
107
- ...defineOverrides(FocusRing, { 'outline-color': 'blue' })('--my-comp'),
108
- } as const
109
- // { 'bg-color': 'blue', '--my-comp-outline-color': 'blue' }
110
- ```
78
+ | Method | Returns |
79
+ | ----------------------------- | ----------------------------------------------------------- |
80
+ | `Result.Success()` | `IResult` — void success |
81
+ | `Result.Success(value)` | `IResultOfT<TValue>` success with value (T inferred) |
82
+ | `Result.Failure(error)` | `IResult` — void failure (Error only) |
83
+ | `Result.Failure<T, E>(error)` | `IResultOfT<T, E>` typed failure (T explicit, E inferred) |
111
84
 
112
- ---
85
+ ## :package: Integration Pattern
113
86
 
114
- ## 通用選項
115
-
116
- 部分函式支援第二個(或第三個)參數傳入 `JSSOptions` 物件來控制行為:
87
+ Bind your error type once and eliminate generic boilerplate:
117
88
 
118
89
  ```ts
119
- interface JSSOptions {
120
- semi?: boolean // 是否在結尾加上分號(;)
121
- prefix?: string // CSS 變數名稱前綴(例如 '--md-badge'
122
- }
90
+ // app-result.ts
91
+ import { Result } from '@sandlada/result';
92
+ import type { IResultOfT } from '@sandlada/result';
93
+ import type { AppError } from './errors.js';
94
+
95
+ export type AppResult<T = void> = IResultOfT<T, AppError>;
96
+
97
+ export const AppResult = {
98
+ Success(): AppResult<void> { return Result.Success() as AppResult<void>; },
99
+ Success<T>(value: T): AppResult<T> { return Result.Success(value) as AppResult<T>; },
100
+ Failure(error: AppError): AppResult<never> { return Result.Failure<never, AppError>(error); },
101
+ } as const;
123
102
  ```
124
103
 
125
- **`semi`** — 加上分號尾綴,適用於需要 inline style 語句的場景。
126
-
127
- **`prefix`** — 為產生的 CSS 變數名稱加上自訂前綴。例如使用 `{ prefix: '--md-badge' }` 時,
128
- `useVars('color-primary', 'blue', { prefix: '--md-badge' })` 會輸出 `var(--md-badge-color-primary, blue)`,
129
- 取代預設的 `var(--color-primary, blue)`。
130
-
131
- > **注意:** `prefix` 僅影響 CSS 變數的**名稱部分**,不影響 Record 的 JavaScript 鍵名。
132
- > 支援 prefix 的函式:`useVars`、`useVarsRecord`、`useInternalVarsRecord`、`useLogicalBorderRadiusVars`、
133
- > `useLogicalBorderRadiusVarsRecord`、`defineLogicalBorderRadiusVars`、`defineTokenRefsRecord`。
134
-
135
- ---
136
-
137
- ## use 系列 — 產生 `var()` 引用
138
-
139
- | 函式 | 說明 | 文件 |
140
- | -------------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
141
- | `useVars(name, fallback, options?)` | 基本變數引用,回傳陣列,支援 `{ semi?, prefix? }` | [docs/use-vars.md](./docs/use-vars.md) |
142
- | `useVarsRecord(name, fallback, options?)` | 基本變數引用,回傳 Record,支援 `{ semi?, prefix? }` | [docs/use-vars-record.md](./docs/use-vars-record.md) |
143
- | `useInternalVars(name, fallback)` | 內部變數(`--_` 前綴)引用,回傳陣列 | [docs/use-internal-vars.md](./docs/use-internal-vars.md) |
144
- | `useInternalVarsRecord(name, fallback, options?)` | 內部變數引用,回傳 Record,支援 `{ semi?, prefix? }` | [docs/use-internal-vars-record.md](./docs/use-internal-vars-record.md) |
145
- | `useLogicalBorderRadiusVars(corner, fallback, options?)` | 邏輯角變數(兩層 `var()` 遞迴),回傳陣列,支援 `{ semi?, prefix? }` | [docs/use-logical-border-radius-vars.md](./docs/use-logical-border-radius-vars.md) |
146
- | `useLogicalBorderRadiusVarsRecord(corner, fallback, options?)` | 邏輯角變數,回傳 Record,支援 `{ semi?, prefix? }` | [docs/use-logical-border-radius-vars-record.md](./docs/use-logical-border-radius-vars-record.md) |
147
-
148
104
  ```ts
149
- import { useVars } from '@sandlada/jss'
105
+ // usage no TError generic anywhere
106
+ import { AppResult } from './app-result.js';
150
107
 
151
- // ['var(--color-primary, blue)']
152
- useVars('color-primary', 'blue')
153
-
154
- // 支援 `var()` 遞迴鏈:
155
- // ['var(--a, var(--b, var(--c, default-value)))']
156
- useVars(['a', 'b', 'c'], 'default-value')
157
-
158
- // Record 模式自動剝除 -- 前綴作為鍵名:
159
- // { 'color-primary': 'var(--color-primary, blue)' }
160
- useVarsRecord('--color-primary', 'blue')
161
-
162
- // 使用 prefix 選項為所有變數名稱加上前綴:
163
- // ['var(--md-badge-color-primary, blue)']
164
- useVars('color-primary', 'blue', { prefix: '--md-badge' })
165
-
166
- // ['var(--md-badge-a, var(--md-badge-b, var(--md-badge-c, default-value)))']
167
- useVars(['a', 'b', 'c'], 'default-value', { prefix: '--md-badge' })
108
+ function getUser(id: string): AppResult<User> {
109
+ if (!id) return AppResult.Failure({ kind: 'Validation', fields: { id: 'Required' } });
110
+ return AppResult.Success({ id, name: 'Alice' });
111
+ }
168
112
  ```
169
113
 
170
- ---
171
-
172
- ## 開發
114
+ ## :ledger: Further Reading
173
115
 
174
- ```bash
175
- # 安裝依賴
176
- npm install
116
+ For detailed documentation — railway-oriented programming, multi-layer error mapping, result aggregation, and C# comparison — see [SPEC.md](./SPEC.md).
177
117
 
178
- # 執行測試
179
- npx vitest
118
+ ## License
180
119
 
181
- # 型別檢查
182
- npx tsc --noEmit
183
- ```
120
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandlada/result",
3
- "version": "0.0.1-20260701.a",
3
+ "version": "0.0.1-20260701.b",
4
4
  "description": "Type-safe Result pattern for TypeScript — explicit error handling without exceptions",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",