Skip to content

Commit c6561a0

Browse files
authored
Merge pull request #215 from nishio/devin/1735797568-translate-japanese-comments
Devin/1735797568 translate japanese comments
2 parents 8fffbb2 + 252ca2b commit c6561a0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2306
-777
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
local_test/
2+
coverage/
3+
docs/

README.md

+129
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,132 @@
44
[![test](https://github.com/takker99/scrapbox-userscript-std/workflows/ci/badge.svg)](https://github.com/takker99/scrapbox-userscript-std/actions?query=workflow%3Aci)
55

66
UNOFFICIAL standard module for Scrapbox UserScript
7+
8+
## Getting Started
9+
10+
This library serves as an unofficial standard library for developing Scrapbox
11+
userscripts. It provides a comprehensive set of utilities for interacting with
12+
Scrapbox's features, including REST API operations, browser interactions, and
13+
common utilities.
14+
15+
### Installation
16+
17+
1. Bundler Configuration This library is distributed through JSR (JavaScript
18+
Registry) and requires a bundler configuration. Follow these steps:
19+
20+
a. Configure your bundler to use JSR:
21+
22+
- For esbuild: Add JSR to your import map
23+
- For other bundlers: Refer to your bundler's JSR integration documentation
24+
25+
b. Import the library:
26+
27+
```typescript
28+
// Import commonly used functions
29+
import { getPage } from "jsr:@cosense/std/rest";
30+
import { parseAbsoluteLink } from "jsr:@cosense/std";
31+
32+
// Import specific modules (recommended)
33+
import { getLinks } from "jsr:@cosense/std/rest";
34+
import { press } from "jsr:@cosense/std/browser/dom";
35+
import { getLines } from "jsr:@cosense/std/browser/dom";
36+
```
37+
38+
2. Module Organization The library is organized into the following main modules:
39+
40+
- `rest/`: API operations for Scrapbox REST endpoints
41+
- Page operations
42+
- Project management
43+
- User authentication
44+
- `browser/`: Browser-side operations
45+
- DOM manipulation
46+
- WebSocket communication
47+
- Event handling
48+
- Core utilities:
49+
- `title`: Title parsing and formatting
50+
- `parseAbsoluteLink`: External link analysis
51+
- Additional helper functions
52+
53+
## Examples
54+
55+
### Basic Usage
56+
57+
1. Retrieving Page Information
58+
59+
```typescript
60+
// Get page content and metadata
61+
import { getPage } from "jsr:@cosense/std/rest";
62+
63+
const result = await getPage("projectName", "pageName");
64+
if (result.ok) {
65+
const page = result.val;
66+
console.log("Page title:", page.title);
67+
console.log("Page content:", page.lines.map((line) => line.text));
68+
console.log("Page descriptions:", page.descriptions.join("\n"));
69+
}
70+
```
71+
72+
2. DOM Operations
73+
74+
```typescript
75+
// Interact with the current page's content
76+
import { getLines, press } from "jsr:@cosense/std/browser/dom";
77+
78+
// Get all lines from the current page
79+
const lines = getLines();
80+
console.log(lines.map((line) => line.text));
81+
82+
// Simulate keyboard input
83+
await press("Enter"); // Add a new line
84+
await press("Tab"); // Indent the line
85+
```
86+
87+
3. External Link Analysis
88+
89+
```typescript
90+
// Parse external links (YouTube, Spotify, etc.)
91+
import { parseAbsoluteLink } from "jsr:@cosense/std";
92+
import type { LinkNode } from "@progfay/scrapbox-parser";
93+
94+
// Create a link node with absolute path type
95+
const link = {
96+
type: "link" as const,
97+
pathType: "absolute" as const,
98+
href: "https://www.youtube.com/watch?v=xxxxx",
99+
content: "",
100+
raw: "[https://www.youtube.com/watch?v=xxxxx]",
101+
} satisfies LinkNode & { pathType: "absolute" };
102+
103+
// Parse and handle different link types
104+
const parsed = parseAbsoluteLink(link);
105+
if (parsed?.type === "youtube") {
106+
// Handle YouTube links
107+
console.log("YouTube video ID:", parsed.href.split("v=")[1]);
108+
const params = new URLSearchParams(parsed.href.split("?")[1]);
109+
const start = params.get("t");
110+
if (start) {
111+
console.log("Video timestamp:", start);
112+
}
113+
} else if (parsed?.type === "spotify") {
114+
// Handle Spotify links
115+
const match = parsed.href.match(/spotify\.com\/track\/([^?]+)/);
116+
if (match) {
117+
console.log("Spotify track ID:", match[1]);
118+
}
119+
}
120+
```
121+
122+
### Important Notes
123+
124+
- This library requires a bundler for use in userscripts
125+
- Full TypeScript support with type definitions included
126+
- Comprehensive error handling with type-safe responses
127+
- For more examples and use cases, see the
128+
[Examples](https://github.com/takker99/scrapbox-userscript-std/tree/main/examples)
129+
directory
130+
131+
### Additional Resources
132+
133+
- [JSR Package Page](https://jsr.io/@cosense/std)
134+
- [API Documentation](https://jsr.io/@cosense/std/doc)
135+
- [GitHub Repository](https://github.com/takker99/scrapbox-userscript-std)

browser/dom/_internal.ts

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
1-
/** 等値比較用に`AddEventListenerOptions`をencodeする */
1+
/**
2+
* Encodes {@linkcode AddEventListenerOptions} into a number for equality comparison.
3+
* This function converts the options object into a single number where each bit
4+
* represents a specific option (capture, once, passive).
5+
*/
26
export const encode = (
37
options: AddEventListenerOptions | boolean | undefined,
48
): number => {
59
if (options === undefined) return 0;
610
if (typeof options === "boolean") return Number(options);
7-
// 各フラグをビットにエンコードする
11+
// Encode each flag into its corresponding bit position
812
return (
913
(options.capture ? 1 : 0) |
1014
(options.once ? 2 : 0) |
1115
(options.passive ? 4 : 0)
1216
);
1317
};
14-
/** 等値比較用にencodeした`AddEventListenerOptions`をdecodeする
18+
/**
19+
* Decodes a number back into {@linkcode AddEventListenerOptions} object.
20+
* Each bit in the encoded number represents a specific option:
1521
*
16-
* - `capture`: `0b001`
17-
* - `once`: `0b010`
18-
* - `passive`: `0b100`
19-
* - `0`: `undefined`
22+
* - `capture`: `0b001` (bit 0)
23+
* - `once`: `0b010` (bit 1)
24+
* - `passive`: `0b100` (bit 2)
25+
* - `0`: returns `undefined`
2026
*
21-
* @param encoded `AddEventListenerOptions`をencodeした値
22-
* @returns `AddEventListenerOptions`または`undefined`
27+
* @param encoded The number containing encoded {@linkcode AddEventListenerOptions} flags
28+
* @returns An {@linkcode AddEventListenerOptions} object or {@linkcode undefined} if encoded value is 0
2329
*/
2430
export const decode = (
2531
encoded: number,

browser/dom/cache.ts

+23-17
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
/** scrapbox.ioが管理しているcache storageから、最新のresponseを取得する
1+
/** Retrieves the latest response from the cache storage managed by scrapbox.io
22
*
3-
* ほぼ https://scrapbox.io/daiiz/ScrapboxでのServiceWorkerとCacheの活用#5d2efaffadf4e70000651173 のパクリ
3+
* This function searches through the cache storage in reverse chronological order
4+
* to find the most recent cached response for a given request.
45
*
5-
* @param request このrequestに対応するresponseが欲しい
6-
* @param options search paramsを無視したいときとかに使う
7-
* @return cacheがあればそのresponseを、なければ`undefined`を返す
6+
* > [!NOTE]
7+
* > Implementation inspired by Scrapbox's ServiceWorker and Cache usage pattern.
8+
* > For details, see the article "ServiceWorker and Cache Usage in Scrapbox" {@see https://scrapbox.io/daiiz/ScrapboxでのServiceWorkerとCacheの活用#5d2efaffadf4e70000651173}
9+
*
10+
* @param request - The {@linkcode Request} to find a cached response for
11+
* @param options - {@linkcode CacheQueryOptions} (e.g., to ignore search params)
12+
* @returns A {@linkcode Response} if found, otherwise {@linkcode undefined}
813
*/
914
export const findLatestCache = async (
1015
request: Request,
@@ -19,10 +24,10 @@ export const findLatestCache = async (
1924
}
2025
};
2126

22-
/** scrapbox.ioが管理しているREST API系のcache storageにresponseを保存する
27+
/** Saves a response to the REST API cache storage managed by scrapbox.io
2328
*
24-
* @param request このrequestに対応するresponseを保存する
25-
* @param response 保存するresponse
29+
* @param request The {@linkcode Request} to associate with the cached response
30+
* @param response The {@linkcode Response} to cache
2631
*/
2732
export const saveApiCache = async (
2833
request: Request,
@@ -38,27 +43,28 @@ export const generateCacheName = (date: Date): string =>
3843
`${date.getDate()}`.padStart(2, "0")
3944
}`;
4045

41-
/** prefetchを実行する
42-
*
43-
* prefetchしたデータは`"prefetch"`と`"api-yyyy-MM-dd"`に格納される
46+
/** Executes prefetch operations for specified API URLs
4447
*
45-
* `"prefetch"`に格納されたデータは、次回のリクエストで返却されたときに削除される
48+
* Prefetched data is stored in two locations:
49+
* 1. `"prefetch"` cache - temporary storage, cleared after first use
50+
* 2. `"api-yyyy-MM-dd"` cache - date-based persistent storage
4651
*
47-
* 回線が遅いときは例外を投げる
52+
* > [!NOTE]
53+
* > Throws an exception if the network connection is slow
4854
*
49-
* @param urls prefetchしたいAPIのURLのリスト
55+
* @param urls List of API URLs to prefetch
5056
*/
5157
export const prefetch = (urls: (string | URL)[]): Promise<void> =>
5258
postMessage({
5359
title: "prefetch",
5460
body: { urls: urls.map((url) => url.toString()) },
5561
});
5662

57-
/** 指定したAPIのcacheの更新を依頼する
63+
/** Requests a cache update for the specified API
5864
*
59-
* 更新は10秒ごとに1つずつ実行される
65+
* Updates are processed one at a time with a 10-second interval between each update
6066
*
61-
* @param cacheしたいAPIのURL
67+
* @param url The URL of the API to cache
6268
*/
6369
export const fetchApiCache = (url: string): Promise<void> =>
6470
postMessage({ title: "fetchApiCache", body: { url } });

browser/dom/caret.ts

+23-15
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
import { textInput } from "./dom.ts";
22

3-
/** editor上の位置情報 */
3+
/** Position information within the editor
4+
*
5+
* @see {@linkcode Range} for selection range information
6+
*/
47
export interface Position {
5-
/** 行数 */ line: number;
6-
/** 何文字目の後ろにいるか */ char: number;
8+
/** Line number (1-based) */ line: number;
9+
/** Character offset within the line (0-based) */ char: number;
710
}
811

9-
/** 選択範囲を表すデータ
12+
/** Represents a text selection range in the editor
13+
*
14+
* When no text is selected, {@linkcode start} and {@linkcode end} positions are the same (cursor position)
1015
*
11-
* 選択範囲がないときは、開始と終了が同じ位置になる
16+
* @see {@linkcode Position} for position type details
1217
*/
1318
export interface Range {
14-
/** 選択範囲の開始位置 */ start: Position;
15-
/** 選択範囲の終了位置 */ end: Position;
19+
/** Starting position of the selection */ start: Position;
20+
/** Ending position of the selection */ end: Position;
1621
}
1722

18-
/** #text-inputを構築しているReact Componentに含まれるカーソルの情報 */
23+
/** Cursor information contained within the React Component that builds `#text-input` */
1924
export interface CaretInfo {
20-
/** カーソルの位置 */ position: Position;
21-
/** 選択範囲中の文字列 */ selectedText: string;
22-
/** 選択範囲の位置 */ selectionRange: Range;
25+
/** Current cursor position */ position: Position;
26+
/** Currently selected text */ selectedText: string;
27+
/** Range of the current selection */ selectionRange: Range;
2328
}
2429

2530
interface ReactFiber {
@@ -32,10 +37,13 @@ interface ReactFiber {
3237
};
3338
}
3439

35-
/** 現在のカーソルと選択範囲の位置情報を取得する
40+
/** Retrieves the current cursor position and text selection information
3641
*
37-
* @return カーソルと選択範囲の情報
38-
* @throws {Error} #text-inputとReact Componentの隠しpropertyが見つからなかった
42+
* @returns A {@linkcode CaretPosition} containing cursor position and text selection information
43+
* @throws {@linkcode Error} when:
44+
* - `#text-input` element is not found
45+
* - React Component's internal properties are not found
46+
* @see {@linkcode CaretInfo} for return type details
3947
*/
4048
export const caret = (): CaretInfo => {
4149
const textarea = textInput();
@@ -51,7 +59,7 @@ export const caret = (): CaretInfo => {
5159
);
5260
}
5361

54-
// @ts-ignore DOMを無理矢理objectとして扱っている
62+
// @ts-ignore Forcefully treating DOM element as an object to access React internals
5563
return (textarea[
5664
reactKey
5765
] as ReactFiber).return.return.stateNode.props;

browser/dom/click.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ export const click = async (
3030
element.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
3131
element.dispatchEvent(new MouseEvent("click", mouseOptions));
3232

33-
// ScrapboxのReactの処理が終わるまで少し待つ
34-
// 待ち時間は感覚で決めた
33+
// Wait for Scrapbox's React event handlers to complete
34+
// Note: 10ms delay is determined empirically to ensure reliable event processing
3535
await delay(10);
3636
};
3737

@@ -72,7 +72,7 @@ export const holdDown = async (
7272
element.dispatchEvent(new TouchEvent("touchend", mouseOptions));
7373
element.dispatchEvent(new MouseEvent("click", mouseOptions));
7474

75-
// ScrapboxのReactの処理が終わるまで少し待つ
76-
// 待ち時間は感覚で決めた
75+
// Wait for Scrapbox's React event handlers to complete
76+
// Note: 10ms delay is determined empirically to ensure reliable event processing
7777
await delay(10);
7878
};

0 commit comments

Comments
 (0)