soseki 0.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.
- package/.config/_is-debug-mode.ts +9 -0
- package/.config/dependency-cruiser.cjs +408 -0
- package/.config/env.d.ts +8 -0
- package/.config/mise.toml +28 -0
- package/.config/navigation-api.d.ts +18 -0
- package/.config/tsconfig.build.json +28 -0
- package/.config/tsconfig.config.json +21 -0
- package/.config/tsconfig.test.json +26 -0
- package/.config/tsconfig.web.json +26 -0
- package/.config/vitest.client.ts +30 -0
- package/package.json +45 -0
- package/src/components/action-id.tsx +35 -0
- package/src/components/browser-router.tsx +31 -0
- package/src/components/hidden-input.tsx +39 -0
- package/src/components/outlet.tsx +17 -0
- package/src/components/router.tsx +234 -0
- package/src/contexts/route-context.ts +21 -0
- package/src/contexts/router-context.ts +55 -0
- package/src/core/_action-id-registry.ts +11 -0
- package/src/core/_capture-stack-trace.ts +12 -0
- package/src/core/_compare-route-paths.ts +90 -0
- package/src/core/_create-html-form-element-form-form-data.ts +32 -0
- package/src/core/_encode-pathname.ts +17 -0
- package/src/core/_is-error.ts +16 -0
- package/src/core/_is-promise-like.ts +14 -0
- package/src/core/_match-route-path.ts +39 -0
- package/src/core/_process-routes.ts +56 -0
- package/src/core/_singleton.ts +45 -0
- package/src/core/_unreachable.ts +22 -0
- package/src/core/_use-singleton.ts +24 -0
- package/src/core/_valibot.ts +147 -0
- package/src/core/_weak-id-registry.ts +125 -0
- package/src/core/constants.ts +4 -0
- package/src/core/data-map.types.ts +28 -0
- package/src/core/data-store.types.ts +25 -0
- package/src/core/deferred-promise.ts +408 -0
- package/src/core/errors.ts +680 -0
- package/src/core/expect-history-entry.ts +95 -0
- package/src/core/history-entry-id-schema.ts +27 -0
- package/src/core/history-entry-url-schema.ts +35 -0
- package/src/core/init-loaders.ts +79 -0
- package/src/core/match-routes.ts +91 -0
- package/src/core/readonly-form-data.types.ts +63 -0
- package/src/core/readonly-url.types.ts +156 -0
- package/src/core/redirect-response.ts +36 -0
- package/src/core/route-request.ts +92 -0
- package/src/core/route.types.ts +351 -0
- package/src/core/start-actions.ts +274 -0
- package/src/core/start-loaders.ts +254 -0
- package/src/core.ts +43 -0
- package/src/engines/engine.types.ts +216 -0
- package/src/engines/navigation-api-engine.ts +406 -0
- package/src/hooks/_use-route-context.ts +19 -0
- package/src/hooks/_use-router-context.ts +25 -0
- package/src/hooks/use-action-data.ts +37 -0
- package/src/hooks/use-loader-data.ts +28 -0
- package/src/hooks/use-navigate.ts +64 -0
- package/src/hooks/use-params.ts +11 -0
- package/src/hooks/use-pathname.ts +10 -0
- package/src/hooks/use-submit.ts +111 -0
- package/src/soseki.ts +75 -0
- package/src/utils/get-action-id.ts +12 -0
- package/src/utils/href.ts +17 -0
- package/src/utils/redirect.ts +13 -0
- package/src/utils/route-index.ts +70 -0
- package/src/utils/route-route.ts +111 -0
- package/src/utils/set-action-id.ts +14 -0
- package/tests/core/_capture-stack-trace.test.ts +46 -0
- package/tests/core/_compare-route-paths.test.ts +134 -0
- package/tests/core/_encode-pathname.test.ts +77 -0
- package/tests/core/_is-error.test.ts +108 -0
- package/tests/core/_is-promise-like.test.ts +100 -0
- package/tests/core/_match-route-path.test.ts +74 -0
- package/tests/core/_process-routes.test.ts +146 -0
- package/tests/core/_singleton.test.ts +102 -0
- package/tests/core/_unreachable.test.ts +38 -0
- package/tests/core/_use-singleton.test.ts +47 -0
- package/tests/core/_weak-id-registry.test.ts +137 -0
- package/tests/core/deferred-promise.test.ts +218 -0
- package/tests/core/expect-history-entry.test.ts +112 -0
- package/tests/core/init-loaders.test.ts +172 -0
- package/tests/core/match-routes.test.ts +178 -0
- package/tests/core/redirect-response.test.ts +36 -0
- package/tests/core/route-request.test.ts +93 -0
- package/tests/core/start-actions.test.ts +319 -0
- package/tests/core/start-loaders.test.ts +276 -0
- package/tests/engines/navigation-api-engine.test.ts +162 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { parse } from "regexparam";
|
|
2
|
+
import compareRoutePaths from "./_compare-route-paths.js";
|
|
3
|
+
import encodePathname from "./_encode-pathname.js";
|
|
4
|
+
import type { Route, RouteDefinition } from "./route.types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* パスのプレフィックスを考慮しながら再帰的にルートを変換する内部実装です。
|
|
8
|
+
*
|
|
9
|
+
* @param defs 処理対象のルート定義の配列です。
|
|
10
|
+
* @param prefix 親ルートから引き継いだパスのプレフィックスです。
|
|
11
|
+
* @returns 変換後のルート配列です。
|
|
12
|
+
*/
|
|
13
|
+
function processRoutesImpl(routes: readonly RouteDefinition[], prefix = ""): readonly Route[] {
|
|
14
|
+
return routes
|
|
15
|
+
.map(route => {
|
|
16
|
+
const path = encodePathname(prefix + "/" + route.path);
|
|
17
|
+
const isIndex = !route.children;
|
|
18
|
+
const {
|
|
19
|
+
keys: paramKeys,
|
|
20
|
+
pattern: pathPattern,
|
|
21
|
+
} = parse(
|
|
22
|
+
path,
|
|
23
|
+
// インデックスルートでないとき loose オプションを `true` にして子ルートに対してもマッチするようにします。
|
|
24
|
+
!isIndex,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
path,
|
|
29
|
+
index: isIndex,
|
|
30
|
+
children: route.children
|
|
31
|
+
? processRoutesImpl(route.children, path)
|
|
32
|
+
: [],
|
|
33
|
+
component: route.component,
|
|
34
|
+
dataFuncs: (route.dataFunctions || []).map(f => ({
|
|
35
|
+
action: f.action,
|
|
36
|
+
loader: f.loader,
|
|
37
|
+
// 未定義の場合は常に true を返すデフォルト関数を設定します。
|
|
38
|
+
shouldAction: f.shouldAction || (a => a.defaultShouldAction),
|
|
39
|
+
shouldReload: f.shouldReload || (a => a.defaultShouldReload),
|
|
40
|
+
})),
|
|
41
|
+
paramKeys,
|
|
42
|
+
pathPattern,
|
|
43
|
+
};
|
|
44
|
+
})
|
|
45
|
+
.sort((a, b) => compareRoutePaths(a.path, b.path));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ルート定義の配列を再帰的に処理し、実行時に適した `Route` オブジェクトの配列に変換します。
|
|
50
|
+
*
|
|
51
|
+
* @param routes 変換前のルート定義の配列です。
|
|
52
|
+
* @returns 前処理が施された `Route` オブジェクトの配列を返します。
|
|
53
|
+
*/
|
|
54
|
+
export default function processRoutes(routes: readonly RouteDefinition[]): readonly Route[] {
|
|
55
|
+
return processRoutesImpl(routes);
|
|
56
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import isPromiseLike from "./_is-promise-like.js";
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
/**
|
|
5
|
+
* シングルトンインスタンスを管理するためのグローバルなキャッシュマップです。
|
|
6
|
+
*/
|
|
7
|
+
var soseki__singleton: Map<unknown, any> | undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 指定されたキーに基づいて値を一意に保持するシングルトンパターンを提供します。
|
|
12
|
+
*
|
|
13
|
+
* 初回実行時に生成された値をキャッシュし、以降の呼び出しではその値を返します。
|
|
14
|
+
*
|
|
15
|
+
* @template T 生成される値の型です。
|
|
16
|
+
* @param key インスタンスを識別するためのユニークなキーです。
|
|
17
|
+
* @param fn インスタンスを生成するためのファクトリー関数です。
|
|
18
|
+
* @returns キャッシュされた値、または非同期の場合はその解決値を返します。
|
|
19
|
+
*/
|
|
20
|
+
export default function singleton<T>(key: unknown, fn: (...args: any) => T): T | Awaited<T> {
|
|
21
|
+
const cache = globalThis.soseki__singleton ||= new Map<unknown, any>();
|
|
22
|
+
if (cache.has(key)) {
|
|
23
|
+
return cache.get(key);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let returns = fn();
|
|
27
|
+
if (isPromiseLike<T>(returns)) {
|
|
28
|
+
const promise = (async () => {
|
|
29
|
+
try {
|
|
30
|
+
const value = await returns;
|
|
31
|
+
cache.set(key, value);
|
|
32
|
+
return value;
|
|
33
|
+
} catch (ex) {
|
|
34
|
+
// エラーが発生した場合はキャッシュを削除し、エラーを投げます。
|
|
35
|
+
cache.delete(key);
|
|
36
|
+
throw ex;
|
|
37
|
+
}
|
|
38
|
+
})();
|
|
39
|
+
cache.set(key, promise);
|
|
40
|
+
} else {
|
|
41
|
+
cache.set(key, returns);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return cache.get(key);
|
|
45
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import captureStackTrace from "./_capture-stack-trace.js";
|
|
2
|
+
import { UnreachableError } from "./errors.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 網羅性チェックを行うためのユーティリティー関数です。
|
|
6
|
+
*/
|
|
7
|
+
function unreachable(): never;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 網羅性チェックを行うためのユーティリティー関数です。`never` 型の変数に予期せぬ値が代入された場合にエラーを投げます。
|
|
11
|
+
*
|
|
12
|
+
* @param value `never` 型の変数です。ここには到達しないはずの値が入ります。
|
|
13
|
+
*/
|
|
14
|
+
function unreachable(value: never): never;
|
|
15
|
+
|
|
16
|
+
function unreachable(...args: [never?]): never {
|
|
17
|
+
const error = new UnreachableError(args);
|
|
18
|
+
captureStackTrace(error, unreachable);
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default unreachable;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 初期化が一度だけ実行されることを保証するための特殊なシンボルです。`ref.current` の初期値として使用され、値がまだ設定されていない状態を示します。
|
|
5
|
+
*/
|
|
6
|
+
const NONE = Symbol.for("soseki/none");
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* コンポーネントのライフサイクルを通じて、初期化関数 (`fn`) を一度だけ実行し、その結果を保持し続けるカスタムフックです。
|
|
10
|
+
*
|
|
11
|
+
* `useMemo` と異なり、依存配列が存在しないため、再レンダリングやフックの呼び出し順序に関係なく、最初のレンダリング時にのみ初期化が実行されることを保証します。
|
|
12
|
+
*
|
|
13
|
+
* @template T 初期化関数が返す値の型です。
|
|
14
|
+
* @param fn 一度だけ実行される初期化関数です。引数は取りません。
|
|
15
|
+
* @returns 初期化関数が返した、シングルトンとして保持される値です。
|
|
16
|
+
*/
|
|
17
|
+
export default function useSingleton<T>(fn: () => T): T {
|
|
18
|
+
const ref = React.useRef<T | typeof NONE>(NONE);
|
|
19
|
+
if (ref.current === NONE) {
|
|
20
|
+
ref.current = fn();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return ref.current;
|
|
24
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { type InferOutput, rawTransform, type RawTransformAction, safeParse } from "valibot";
|
|
2
|
+
import captureStackTrace from "./_capture-stack-trace.js";
|
|
3
|
+
import isError from "./_is-error.js";
|
|
4
|
+
import { UnexpectedValidationError } from "./errors.js";
|
|
5
|
+
|
|
6
|
+
/***************************************************************************************************
|
|
7
|
+
*
|
|
8
|
+
* 共通の型
|
|
9
|
+
*
|
|
10
|
+
**************************************************************************************************/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Valibot のスキーマの基底型を抽出するための型定義です。
|
|
14
|
+
*/
|
|
15
|
+
type BaseSchema = typeof safeParse extends (schema: infer TSchema, ...args: any) => any ? TSchema
|
|
16
|
+
: never;
|
|
17
|
+
|
|
18
|
+
/***************************************************************************************************
|
|
19
|
+
*
|
|
20
|
+
* 再エクスポート
|
|
21
|
+
*
|
|
22
|
+
**************************************************************************************************/
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
brand,
|
|
26
|
+
minValue,
|
|
27
|
+
nullable,
|
|
28
|
+
number,
|
|
29
|
+
object,
|
|
30
|
+
pipe,
|
|
31
|
+
safeInteger,
|
|
32
|
+
string,
|
|
33
|
+
union,
|
|
34
|
+
url,
|
|
35
|
+
uuid,
|
|
36
|
+
} from "valibot";
|
|
37
|
+
export type { InferInput, InferOutput } from "valibot";
|
|
38
|
+
|
|
39
|
+
/***************************************************************************************************
|
|
40
|
+
*
|
|
41
|
+
* transform
|
|
42
|
+
*
|
|
43
|
+
**************************************************************************************************/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 入力値を変換するアクションを作成します。例外が投げられた場合は Issue として登録します。
|
|
47
|
+
*
|
|
48
|
+
* @template TInput 入力値の型です。
|
|
49
|
+
* @template TOutput 出力値の型です。
|
|
50
|
+
* @param operation 変換処理を行う関数です。
|
|
51
|
+
* @returns Valibot の RawTransformAction オブジェクトです。
|
|
52
|
+
*/
|
|
53
|
+
export function transform<TInput, TOutput>(
|
|
54
|
+
operation: (input: TInput) => TOutput,
|
|
55
|
+
): RawTransformAction<TInput, TOutput> {
|
|
56
|
+
return rawTransform<TInput, TOutput>(({ dataset, addIssue, NEVER }) => {
|
|
57
|
+
const input = dataset.value;
|
|
58
|
+
try {
|
|
59
|
+
return operation(input);
|
|
60
|
+
} catch (ex) {
|
|
61
|
+
let message: string;
|
|
62
|
+
if (isError(ex)) {
|
|
63
|
+
message = `${ex.name}: ${ex.message}`;
|
|
64
|
+
} else {
|
|
65
|
+
try {
|
|
66
|
+
message = JSON.stringify(ex);
|
|
67
|
+
} catch {
|
|
68
|
+
message = String(ex);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
addIssue({
|
|
73
|
+
input,
|
|
74
|
+
message,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return NEVER;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/***************************************************************************************************
|
|
83
|
+
*
|
|
84
|
+
* parse
|
|
85
|
+
*
|
|
86
|
+
**************************************************************************************************/
|
|
87
|
+
|
|
88
|
+
// /**
|
|
89
|
+
// * バリデーションエラーを生成するためのコンストラクター型インターフェースです。
|
|
90
|
+
// */
|
|
91
|
+
// export interface IParseErrorConstructor {
|
|
92
|
+
// new(issues: [Issue, ...Issue[]], input: unknown): ValidationErrorBase<ErrorMeta>;
|
|
93
|
+
// }
|
|
94
|
+
|
|
95
|
+
// /**
|
|
96
|
+
// * 指定されたスキーマに従って入力を検証し、失敗した場合は指定されたエラーを投げます。
|
|
97
|
+
// *
|
|
98
|
+
// * @template TSchema 使用するスキーマの型です。
|
|
99
|
+
// * @param schema 検証に使用する Valibot スキーマです。
|
|
100
|
+
// * @param input 検証対象の入力値です。
|
|
101
|
+
// * @param Error バリデーション失敗時に投げるエラークラスです。デフォルトは InvalidInputError です。
|
|
102
|
+
// * @returns 検証に成功した出力値です。
|
|
103
|
+
// * @throws 検証に失敗した場合、指定された Error を投げます。
|
|
104
|
+
// */
|
|
105
|
+
// export function parse<const TSchema extends BaseSchema>(
|
|
106
|
+
// schema: TSchema,
|
|
107
|
+
// input: unknown,
|
|
108
|
+
// Error: IParseErrorConstructor = InvalidInputError,
|
|
109
|
+
// ): InferOutput<TSchema> {
|
|
110
|
+
// const result = safeParse(schema, input);
|
|
111
|
+
// if (result.success) {
|
|
112
|
+
// return result.output;
|
|
113
|
+
// }
|
|
114
|
+
|
|
115
|
+
// const error = new Error(result.issues, input);
|
|
116
|
+
// captureStackTrace(error, parse);
|
|
117
|
+
// throw error;
|
|
118
|
+
// }
|
|
119
|
+
|
|
120
|
+
/***************************************************************************************************
|
|
121
|
+
*
|
|
122
|
+
* expect
|
|
123
|
+
*
|
|
124
|
+
**************************************************************************************************/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 指定されたスキーマに従って入力を検証し、失敗した場合は UnexpectedValidationError を投げます。
|
|
128
|
+
*
|
|
129
|
+
* @template TSchema 使用するスキーマの型です。
|
|
130
|
+
* @param schema 検証に使用する Valibot スキーマです。
|
|
131
|
+
* @param input 検証対象の入力値です。
|
|
132
|
+
* @returns 検証に成功した出力値です。
|
|
133
|
+
* @throws 検証に失敗した場合、UnexpectedValidationError を投げます。
|
|
134
|
+
*/
|
|
135
|
+
export function expect<const TSchema extends BaseSchema>(
|
|
136
|
+
schema: TSchema,
|
|
137
|
+
input: unknown,
|
|
138
|
+
): InferOutput<TSchema> {
|
|
139
|
+
const result = safeParse(schema, input);
|
|
140
|
+
if (result.success) {
|
|
141
|
+
return result.output;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const error = new UnexpectedValidationError(result.issues, input);
|
|
145
|
+
captureStackTrace(error, expect);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import unreachable from "./_unreachable.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 識別子(ID)の型エイリアスです。
|
|
5
|
+
*
|
|
6
|
+
* ID は増分カウンターを36進数エンコードしたものです。
|
|
7
|
+
*/
|
|
8
|
+
export type Id = string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `WeakIdRegistry` クラスは、オブジェクトに対する ID の割り当てと管理を行います。
|
|
12
|
+
*
|
|
13
|
+
* オブジェクト自体は `WeakMap` と `WeakRef` を使用して保持されるため、参照がなくなったオブジェクトはガベージコレクション(GC)の対象になります。
|
|
14
|
+
*
|
|
15
|
+
* @template TValue ID を割り当てる対象となるオブジェクトの型です。`object` 型のサブタイプである必要があります。
|
|
16
|
+
*/
|
|
17
|
+
export default class WeakIdRegistry<TValue extends object> {
|
|
18
|
+
/**
|
|
19
|
+
* ID 生成のための内部カウンターです。BigInt を使用することで、非常に大きな数値まで ID を生成できます。
|
|
20
|
+
*/
|
|
21
|
+
private counter: bigint;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* オブジェクト (関数を含む) から、割り当てられた ID へのマッピングを保持する `WeakMap` です。
|
|
25
|
+
*
|
|
26
|
+
* `WeakMap` を使用することで、キーであるオブジェクトが他の場所から参照されなくなった場合、このマッピングも自動的に破棄され、GC が可能になります。
|
|
27
|
+
*/
|
|
28
|
+
private readonly v2id: WeakMap<TValue, Id>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* ID から、対応するオブジェクトへの弱い参照 (`WeakRef`) のマッピングを保持する `Map` です。
|
|
32
|
+
*
|
|
33
|
+
* オブジェクト自体が GC される可能性があるため、`WeakRef` を使用しています。
|
|
34
|
+
*/
|
|
35
|
+
private readonly id2v: Map<Id, WeakRef<TValue>>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* オブジェクトが GC されたときに実行されるコールバックを登録するための `FinalizationRegistry` です。
|
|
39
|
+
*
|
|
40
|
+
* オブジェクトが GC されると、登録された ID がコールバックに渡され、その ID に対応するエントリーを `id2v` マップから削除するために使用されます。
|
|
41
|
+
*/
|
|
42
|
+
private readonly gc: FinalizationRegistry<Id>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* `WeakIdRegistry` クラスの新しいインスタンスを作成します。
|
|
46
|
+
*/
|
|
47
|
+
public constructor() {
|
|
48
|
+
this.counter = 0n;
|
|
49
|
+
this.v2id = new WeakMap();
|
|
50
|
+
this.id2v = new Map();
|
|
51
|
+
this.gc = new FinalizationRegistry(id => {
|
|
52
|
+
this.id2v.delete(id);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 指定されたオブジェクトに一意の ID を割り当てて登録します。
|
|
58
|
+
*
|
|
59
|
+
* すでに ID が割り当てられているオブジェクトであれば、既存の ID を返します。
|
|
60
|
+
*
|
|
61
|
+
* @param value ID を割り当てる対象のオブジェクトです。
|
|
62
|
+
* @returns 割り当てられた、または既存の一意の ID です。
|
|
63
|
+
*/
|
|
64
|
+
public set(value: TValue): Id {
|
|
65
|
+
if (!this.v2id.has(value)) {
|
|
66
|
+
const id = (this.counter++).toString(36);
|
|
67
|
+
this.v2id.set(value, id);
|
|
68
|
+
this.id2v.set(id, new WeakRef(value));
|
|
69
|
+
// `FinalizationRegistry` にオブジェクトとそれに対応する ID を登録します。
|
|
70
|
+
// これにより、オブジェクトが GC されたときに `id2v` からエントリーが削除されます。
|
|
71
|
+
this.gc.register(value, id);
|
|
72
|
+
|
|
73
|
+
return id;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const id = this.v2id.get(value)!;
|
|
77
|
+
switch (typeof id) {
|
|
78
|
+
case "string":
|
|
79
|
+
return id;
|
|
80
|
+
default:
|
|
81
|
+
// `id` は必ず文字列になるはずです。
|
|
82
|
+
unreachable(id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 指定されたオブジェクトに ID が割り当てられているかどうかを確認します。
|
|
88
|
+
*
|
|
89
|
+
* @param value 確認するオブジェクトです。
|
|
90
|
+
* @returns ID が割り当てられていれば `true`、そうでなければ `false` を返します。
|
|
91
|
+
*/
|
|
92
|
+
public has(value: TValue): boolean {
|
|
93
|
+
return this.v2id.has(value);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 指定されたオブジェクトに対応する ID を取得します。
|
|
98
|
+
*
|
|
99
|
+
* オブジェクトが未登録の場合は `undefined` を返します。
|
|
100
|
+
*
|
|
101
|
+
* @param value 取得したい ID のオブジェクトです。
|
|
102
|
+
* @returns 対応する ID、またはオブジェクトが未登録の場合は `undefined` を返します。
|
|
103
|
+
*/
|
|
104
|
+
public get(value: TValue): Id | undefined;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 指定された ID に対応するオブジェクトを取得します。
|
|
108
|
+
*
|
|
109
|
+
* オブジェクトが既に GC されている場合は `undefined` を返します。
|
|
110
|
+
*
|
|
111
|
+
* @param id 取得したいオブジェクトの ID です。
|
|
112
|
+
* @returns 対応するオブジェクト、またはオブジェクトが GC されている場合は `undefined` を返します。
|
|
113
|
+
*/
|
|
114
|
+
public get(id: Id): TValue | undefined;
|
|
115
|
+
|
|
116
|
+
public get(idOrValue: Id | TValue): unknown {
|
|
117
|
+
if (typeof idOrValue === "string") {
|
|
118
|
+
const id = idOrValue;
|
|
119
|
+
return this.id2v.get(id)?.deref();
|
|
120
|
+
} else {
|
|
121
|
+
const value = idOrValue;
|
|
122
|
+
return this.v2id.get(value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type DeferredPromise from "./deferred-promise.js";
|
|
2
|
+
import type { IAction, ILoader } from "./route.types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 読み取り専用のデータマップを表すインターフェースです。
|
|
6
|
+
*
|
|
7
|
+
* ルートに関連付けられたアクションやローダーの関数をキーとし、その実行結果を値として保持します。
|
|
8
|
+
*
|
|
9
|
+
* @template TDataFunction アクションまたはローダーの型定義です。デフォルトは `IAction | ILoader` です。
|
|
10
|
+
* @template TData 遅延評価されるプロミスの型定義です。デフォルトは `DeferredPromise<unknown>` です。
|
|
11
|
+
*/
|
|
12
|
+
export interface IReadonlyDataMap<
|
|
13
|
+
TDataFunction extends IAction | ILoader = IAction | ILoader,
|
|
14
|
+
TData = DeferredPromise<unknown>,
|
|
15
|
+
> extends ReadonlyMap<TDataFunction, TData> {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 書き込み可能なデータマップを表すインターフェースです。
|
|
19
|
+
*
|
|
20
|
+
* ルートに関連付けられたアクションやローダーの関数をキーとし、その実行結果を値として保持・操作します。
|
|
21
|
+
*
|
|
22
|
+
* @template TDataFunction アクションまたはローダーの型定義です。デフォルトは `IAction | ILoader` です。
|
|
23
|
+
* @template TData 遅延評価されるプロミスの型定義です。デフォルトは `DeferredPromise<unknown>` です。
|
|
24
|
+
*/
|
|
25
|
+
export interface IDataMap<
|
|
26
|
+
TDataFunction extends IAction | ILoader = IAction | ILoader,
|
|
27
|
+
TData = DeferredPromise<unknown>,
|
|
28
|
+
> extends Map<TDataFunction, TData> {}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IDataMap } from "./data-map.types.js";
|
|
2
|
+
import type { HistoryEntryId } from "./history-entry-id-schema.js";
|
|
3
|
+
import type { IAction, ILoader } from "./route.types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 読み取り専用のデータストアを表すインターフェースです。
|
|
7
|
+
*
|
|
8
|
+
* 履歴エントリーの ID をキーとし、それに関連付けられたデータマップを値として管理します。
|
|
9
|
+
*
|
|
10
|
+
* @template TDataFunction データマップ内で使用されるアクションまたはローダーの型定義です。
|
|
11
|
+
*/
|
|
12
|
+
export interface IReadonlyDataStore<TDataFunction extends IAction | ILoader = IAction | ILoader>
|
|
13
|
+
extends Readonly<Map<HistoryEntryId, IDataMap<TDataFunction>>>
|
|
14
|
+
{}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 書き込み可能なデータストアを表すインターフェースです。
|
|
18
|
+
*
|
|
19
|
+
* 履歴エントリーの ID ごとに、ルートに関連するデータの読み書きを行います。
|
|
20
|
+
*
|
|
21
|
+
* @template TDataFunction データマップ内で使用されるアクションまたはローダーの型定義です。
|
|
22
|
+
*/
|
|
23
|
+
export interface IDataStore<TDataFunction extends IAction | ILoader = IAction | ILoader>
|
|
24
|
+
extends Map<HistoryEntryId, IDataMap<TDataFunction>>
|
|
25
|
+
{}
|