c063 1.4.8 → 1.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.
- package/dist/types/index.d.ts +5 -5
- package/dist/utils/index.d.ts +38 -13
- package/dist/utils/index.js +106 -28
- package/package.json +1 -1
- package/src/types/{index.ts → index.tsx} +5 -5
- package/src/utils/index.tsx +115 -28
package/dist/types/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { AsComponentProps, OverrideProps } from "./common";
|
|
|
7
7
|
*
|
|
8
8
|
* 類型分為以下幾大類:
|
|
9
9
|
*
|
|
10
|
-
* - `keyword1` / `keyword2`: 關鍵字,如 `const
|
|
10
|
+
* - `keyword1` / `keyword2`: 關鍵字,如 `const`/`return`、`import` 等,分顏色類別。
|
|
11
11
|
* - `string`: 字串常值,如 `'text'`、`"value"`。
|
|
12
12
|
* - `number`: 數字常值,如 `123`、`3.14`。
|
|
13
13
|
* - `comment`: 註解內容,如 `//`。
|
|
@@ -47,7 +47,7 @@ export type CodeTokenProps<T extends React.ElementType> = AsComponentProps<T, {
|
|
|
47
47
|
*/
|
|
48
48
|
theme?: CodeTheme;
|
|
49
49
|
}>;
|
|
50
|
-
export type CodeTokenBuilder = <T extends React.ElementType>(children: CodeTokenProps<T>["children"], props?: CodeTokenProps<T>) => CodeTokenProps<T>;
|
|
50
|
+
export type CodeTokenBuilder = <T extends React.ElementType = "span">(children: CodeTokenProps<T>["children"], props?: CodeTokenProps<T>) => CodeTokenProps<T>;
|
|
51
51
|
/**
|
|
52
52
|
* 用於單一程式碼行的屬性,用在 <CodeLine /> 或類似元件中。
|
|
53
53
|
*/
|
|
@@ -80,13 +80,13 @@ export type CodeBlockProps<T extends React.ElementType> = OverrideProps<React.HT
|
|
|
80
80
|
* ```tsx
|
|
81
81
|
* <CodeBlock tokenLines={[
|
|
82
82
|
* [
|
|
83
|
-
* { type: "
|
|
83
|
+
* { type: "keyword1", children: "const" },
|
|
84
84
|
* { type: "variable", children: "x" },
|
|
85
85
|
* { type: "operator", children: "=" },
|
|
86
86
|
* { type: "number", children: "42" },
|
|
87
87
|
* ],
|
|
88
88
|
* [
|
|
89
|
-
* { type: "
|
|
89
|
+
* { type: "keyword2", children: "return" },
|
|
90
90
|
* { type: "variable", children: "x" },
|
|
91
91
|
* ],
|
|
92
92
|
* ]} />
|
|
@@ -109,7 +109,7 @@ export type CodeBlockProps<T extends React.ElementType> = OverrideProps<React.HT
|
|
|
109
109
|
lineNumberStyle?: React.CSSProperties;
|
|
110
110
|
/**
|
|
111
111
|
* 語法主題名稱。
|
|
112
|
-
* @default "
|
|
112
|
+
* @default "default-dark-modern"
|
|
113
113
|
*/
|
|
114
114
|
theme?: CodeTheme;
|
|
115
115
|
}>;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,31 +1,56 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CodeTokenBuilder, CodeTokenProps, CodeTokenType } from "../types";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* `c063` 是一組語法高亮 token 建構器集合。
|
|
5
|
+
* 每個 key 對應一種語法分類(如 `keyword1`, `string`, `comment` 等),
|
|
6
|
+
* 回傳對應的 `CodeTokenProps` 物件。
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
+
* @example
|
|
8
9
|
* ```tsx
|
|
9
|
-
* c063.keyword1("const")
|
|
10
|
-
* c063.string("'
|
|
10
|
+
* const keyword = c063.keyword1("const");
|
|
11
|
+
* const str = c063.string("'Hello'", { as: "code" });
|
|
11
12
|
* ```
|
|
12
13
|
*
|
|
13
|
-
* @
|
|
14
|
-
* tokens.push(c063.keyword1("const"));
|
|
15
|
-
* tokens.push(c063.string("'Hello'"));
|
|
16
|
-
*
|
|
17
|
-
* @returns 一個以 `CodeTokenType` 為 key 的建構器函式集合
|
|
14
|
+
* @returns 以 `CodeTokenType` 為 key 的建構器函式集合。
|
|
18
15
|
*/
|
|
19
16
|
declare const c063: Record<CodeTokenType, CodeTokenBuilder>;
|
|
17
|
+
export default c063;
|
|
20
18
|
/**
|
|
21
|
-
* 產生指定空白數量的 CodeToken
|
|
19
|
+
* 產生指定空白數量的 CodeToken,用於縮排、空格等用途。
|
|
22
20
|
*
|
|
23
21
|
* @param count 空白字元數,預設為 1
|
|
24
|
-
* @returns
|
|
22
|
+
* @returns type 為 `"default"`、內容為空格的 `CodeTokenProps`
|
|
25
23
|
*
|
|
26
24
|
* @example
|
|
25
|
+
* ```tsx
|
|
27
26
|
* tokens.push(whiteSpace(2)); // -> { type: "default", children: " " }
|
|
27
|
+
* ```
|
|
28
28
|
*/
|
|
29
29
|
export declare const whiteSpace: (count?: number) => CodeTokenProps<"span">;
|
|
30
|
+
/**
|
|
31
|
+
* 抽取單個 `CodeTokenProps` 的純文字內容。
|
|
32
|
+
*
|
|
33
|
+
* @param token 要處理的 token
|
|
34
|
+
* @returns 對應的文字內容
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* extractTokenContent(c063.keyword1("return")); // => "return"
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
30
41
|
export declare const extractTokenContent: <T extends React.ElementType>(token: CodeTokenProps<T>) => string;
|
|
31
|
-
|
|
42
|
+
/**
|
|
43
|
+
* 判斷兩個 token 是否相等(type 與內容皆相同)。
|
|
44
|
+
*
|
|
45
|
+
* @param a 第一個 token
|
|
46
|
+
* @param b 第二個 token
|
|
47
|
+
* @returns 是否相等
|
|
48
|
+
*/
|
|
49
|
+
export declare const isTokenEqual: <T extends React.ElementType>(a: CodeTokenProps<T>, b: CodeTokenProps<T>) => boolean;
|
|
50
|
+
/**
|
|
51
|
+
* 將 token 列表按語法類型分類。
|
|
52
|
+
*
|
|
53
|
+
* @param lines 二維陣列,每行為一組 token
|
|
54
|
+
* @returns 分組後的 token 映射,key 為 `CodeTokenType`
|
|
55
|
+
*/
|
|
56
|
+
export declare const groupTokensByType: <T extends React.ElementType>(lines: CodeTokenProps<T>[][]) => Record<CodeTokenType, CodeTokenProps<T>[]>;
|
package/dist/utils/index.js
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* `c063` 是一組語法高亮 token 建構器集合。
|
|
4
|
+
* 每個 key 對應一種語法分類(如 `keyword1`, `string`, `comment` 等),
|
|
5
|
+
* 回傳對應的 `CodeTokenProps` 物件。
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
+
* @example
|
|
7
8
|
* ```tsx
|
|
8
|
-
* c063.keyword1("const")
|
|
9
|
-
* c063.string("'
|
|
9
|
+
* const keyword = c063.keyword1("const");
|
|
10
|
+
* const str = c063.string("'Hello'", { as: "code" });
|
|
10
11
|
* ```
|
|
11
12
|
*
|
|
12
|
-
* @
|
|
13
|
-
* tokens.push(c063.keyword1("const"));
|
|
14
|
-
* tokens.push(c063.string("'Hello'"));
|
|
15
|
-
*
|
|
16
|
-
* @returns 一個以 `CodeTokenType` 為 key 的建構器函式集合
|
|
13
|
+
* @returns 以 `CodeTokenType` 為 key 的建構器函式集合。
|
|
17
14
|
*/
|
|
18
15
|
const c063 = new Proxy({}, {
|
|
19
16
|
get: (_, prop) => {
|
|
17
|
+
/**
|
|
18
|
+
* 建立指定語法類型的 CodeToken。
|
|
19
|
+
*
|
|
20
|
+
* @param children 要包裹的 React 內容或字串
|
|
21
|
+
* @param props 可選的額外屬性,如 `as` 或 `className`
|
|
22
|
+
* @returns 一個 CodeToken 物件
|
|
23
|
+
*/
|
|
20
24
|
const builder = (children, props) => {
|
|
21
25
|
return {
|
|
22
26
|
children,
|
|
@@ -27,39 +31,113 @@ const c063 = new Proxy({}, {
|
|
|
27
31
|
return builder;
|
|
28
32
|
},
|
|
29
33
|
});
|
|
34
|
+
export default c063;
|
|
30
35
|
/**
|
|
31
|
-
* 產生指定空白數量的 CodeToken
|
|
36
|
+
* 產生指定空白數量的 CodeToken,用於縮排、空格等用途。
|
|
32
37
|
*
|
|
33
38
|
* @param count 空白字元數,預設為 1
|
|
34
|
-
* @returns
|
|
39
|
+
* @returns type 為 `"default"`、內容為空格的 `CodeTokenProps`
|
|
35
40
|
*
|
|
36
41
|
* @example
|
|
42
|
+
* ```tsx
|
|
37
43
|
* tokens.push(whiteSpace(2)); // -> { type: "default", children: " " }
|
|
44
|
+
* ```
|
|
38
45
|
*/
|
|
39
46
|
export const whiteSpace = (count = 1) => c063.default(" ".repeat(count));
|
|
47
|
+
/**
|
|
48
|
+
* 遞迴抽取 ReactNode 中的純文字內容。
|
|
49
|
+
*
|
|
50
|
+
* @param children ReactNode,可以是字串、數字、JSX 元素、陣列等
|
|
51
|
+
* @returns 純文字內容字串
|
|
52
|
+
*/
|
|
53
|
+
const _extractReactNode = (children) => {
|
|
54
|
+
if (typeof children === "string")
|
|
55
|
+
return children;
|
|
56
|
+
if (typeof children === "number")
|
|
57
|
+
return children.toString();
|
|
58
|
+
if (Array.isArray(children))
|
|
59
|
+
return children.map(_extractReactNode).join("");
|
|
60
|
+
if (React.isValidElement(children)) {
|
|
61
|
+
return _extractReactNode(children.props.children);
|
|
62
|
+
}
|
|
63
|
+
if (typeof children === "object" && children !== null) {
|
|
64
|
+
return React.Children.toArray(children).map(_extractReactNode).join("");
|
|
65
|
+
}
|
|
66
|
+
return ""; // 如果 children 是 null 或 undefined,則返回空字串
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* 抽取單個 `CodeTokenProps` 的純文字內容。
|
|
70
|
+
*
|
|
71
|
+
* @param token 要處理的 token
|
|
72
|
+
* @returns 對應的文字內容
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* extractTokenContent(c063.keyword1("return")); // => "return"
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
40
79
|
export const extractTokenContent = (token) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
80
|
+
return _extractReactNode(token.children);
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* 判斷兩個 token 是否相等(type 與內容皆相同)。
|
|
84
|
+
*
|
|
85
|
+
* @param a 第一個 token
|
|
86
|
+
* @param b 第二個 token
|
|
87
|
+
* @returns 是否相等
|
|
88
|
+
*/
|
|
89
|
+
export const isTokenEqual = (a, b) => {
|
|
90
|
+
return a.type === b.type && extractTokenContent(a) === extractTokenContent(b);
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* 將 token 列表按語法類型分類。
|
|
94
|
+
*
|
|
95
|
+
* @param lines 二維陣列,每行為一組 token
|
|
96
|
+
* @returns 分組後的 token 映射,key 為 `CodeTokenType`
|
|
97
|
+
*/
|
|
98
|
+
export const groupTokensByType = (lines) => {
|
|
99
|
+
var _a;
|
|
100
|
+
const grouped = {
|
|
101
|
+
keyword1: [],
|
|
102
|
+
keyword2: [],
|
|
103
|
+
function: [],
|
|
104
|
+
string: [],
|
|
105
|
+
number: [],
|
|
106
|
+
comment: [],
|
|
107
|
+
type: [],
|
|
108
|
+
variable: [],
|
|
109
|
+
constant: [],
|
|
110
|
+
brackets1: [],
|
|
111
|
+
brackets2: [],
|
|
112
|
+
brackets3: [],
|
|
113
|
+
operator: [],
|
|
114
|
+
default: [],
|
|
52
115
|
};
|
|
53
|
-
|
|
116
|
+
for (const token of lines.flat()) {
|
|
117
|
+
grouped[(_a = token.type) !== null && _a !== void 0 ? _a : "default"].push(token);
|
|
118
|
+
}
|
|
119
|
+
return grouped;
|
|
54
120
|
};
|
|
55
|
-
export default c063;
|
|
56
121
|
/**
|
|
57
|
-
*
|
|
122
|
+
* 待實作
|
|
123
|
+
* `parseTokens` 是語法解析器的代理集合,用來解析特定語言的程式碼字串。
|
|
124
|
+
*
|
|
125
|
+
* 每個 key 對應一種可解析語言(如 `"javascript"`、`"python"` 等),
|
|
126
|
+
* 傳入原始程式碼字串後,回傳解析後的 token 二維陣列(每行一組 token)。
|
|
127
|
+
*
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const tokens = parseTokens.javascript("const x = 1;");
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @returns 語法高亮用的 `CodeTokenProps` 二維陣列
|
|
58
135
|
*/
|
|
59
|
-
const
|
|
136
|
+
const parseTokens = new Proxy({}, {
|
|
60
137
|
get: (_, prop) => {
|
|
61
138
|
const parser = (content) => {
|
|
62
|
-
|
|
139
|
+
const result = [];
|
|
140
|
+
return result;
|
|
63
141
|
};
|
|
64
142
|
return parser;
|
|
65
143
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "c063",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "A React component for displaying code snippets with syntax highlighting.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -7,7 +7,7 @@ import { AsComponentProps, OverrideProps } from "./common";
|
|
|
7
7
|
*
|
|
8
8
|
* 類型分為以下幾大類:
|
|
9
9
|
*
|
|
10
|
-
* - `keyword1` / `keyword2`: 關鍵字,如 `const
|
|
10
|
+
* - `keyword1` / `keyword2`: 關鍵字,如 `const`/`return`、`import` 等,分顏色類別。
|
|
11
11
|
* - `string`: 字串常值,如 `'text'`、`"value"`。
|
|
12
12
|
* - `number`: 數字常值,如 `123`、`3.14`。
|
|
13
13
|
* - `comment`: 註解內容,如 `//`。
|
|
@@ -64,7 +64,7 @@ export type CodeTokenProps<T extends React.ElementType> = AsComponentProps<
|
|
|
64
64
|
}
|
|
65
65
|
>;
|
|
66
66
|
|
|
67
|
-
export type CodeTokenBuilder = <T extends React.ElementType>(
|
|
67
|
+
export type CodeTokenBuilder = <T extends React.ElementType = "span">(
|
|
68
68
|
children: CodeTokenProps<T>["children"],
|
|
69
69
|
props?: CodeTokenProps<T>
|
|
70
70
|
) => CodeTokenProps<T>;
|
|
@@ -107,13 +107,13 @@ export type CodeBlockProps<T extends React.ElementType> = OverrideProps<
|
|
|
107
107
|
* ```tsx
|
|
108
108
|
* <CodeBlock tokenLines={[
|
|
109
109
|
* [
|
|
110
|
-
* { type: "
|
|
110
|
+
* { type: "keyword1", children: "const" },
|
|
111
111
|
* { type: "variable", children: "x" },
|
|
112
112
|
* { type: "operator", children: "=" },
|
|
113
113
|
* { type: "number", children: "42" },
|
|
114
114
|
* ],
|
|
115
115
|
* [
|
|
116
|
-
* { type: "
|
|
116
|
+
* { type: "keyword2", children: "return" },
|
|
117
117
|
* { type: "variable", children: "x" },
|
|
118
118
|
* ],
|
|
119
119
|
* ]} />
|
|
@@ -137,7 +137,7 @@ export type CodeBlockProps<T extends React.ElementType> = OverrideProps<
|
|
|
137
137
|
lineNumberStyle?: React.CSSProperties;
|
|
138
138
|
/**
|
|
139
139
|
* 語法主題名稱。
|
|
140
|
-
* @default "
|
|
140
|
+
* @default "default-dark-modern"
|
|
141
141
|
*/
|
|
142
142
|
theme?: CodeTheme;
|
|
143
143
|
}
|
package/src/utils/index.tsx
CHANGED
|
@@ -7,28 +7,32 @@ import {
|
|
|
7
7
|
} from "../types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* `c063` 是一組語法高亮 token 建構器集合。
|
|
11
|
+
* 每個 key 對應一種語法分類(如 `keyword1`, `string`, `comment` 等),
|
|
12
|
+
* 回傳對應的 `CodeTokenProps` 物件。
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
+
* @example
|
|
14
15
|
* ```tsx
|
|
15
|
-
* c063.keyword1("const")
|
|
16
|
-
* c063.string("'
|
|
16
|
+
* const keyword = c063.keyword1("const");
|
|
17
|
+
* const str = c063.string("'Hello'", { as: "code" });
|
|
17
18
|
* ```
|
|
18
19
|
*
|
|
19
|
-
* @
|
|
20
|
-
* tokens.push(c063.keyword1("const"));
|
|
21
|
-
* tokens.push(c063.string("'Hello'"));
|
|
22
|
-
*
|
|
23
|
-
* @returns 一個以 `CodeTokenType` 為 key 的建構器函式集合
|
|
20
|
+
* @returns 以 `CodeTokenType` 為 key 的建構器函式集合。
|
|
24
21
|
*/
|
|
25
22
|
const c063 = new Proxy(
|
|
26
23
|
{},
|
|
27
24
|
{
|
|
28
25
|
get: (_, prop: CodeTokenType) => {
|
|
26
|
+
/**
|
|
27
|
+
* 建立指定語法類型的 CodeToken。
|
|
28
|
+
*
|
|
29
|
+
* @param children 要包裹的 React 內容或字串
|
|
30
|
+
* @param props 可選的額外屬性,如 `as` 或 `className`
|
|
31
|
+
* @returns 一個 CodeToken 物件
|
|
32
|
+
*/
|
|
29
33
|
const builder = <T extends React.ElementType = "span">(
|
|
30
34
|
children: React.ReactNode,
|
|
31
|
-
props
|
|
35
|
+
props?: CodeTokenProps<T>
|
|
32
36
|
) => {
|
|
33
37
|
return {
|
|
34
38
|
children,
|
|
@@ -36,50 +40,133 @@ const c063 = new Proxy(
|
|
|
36
40
|
...props,
|
|
37
41
|
};
|
|
38
42
|
};
|
|
39
|
-
return builder
|
|
43
|
+
return builder;
|
|
40
44
|
},
|
|
41
45
|
}
|
|
42
46
|
) as Record<CodeTokenType, CodeTokenBuilder>;
|
|
47
|
+
export default c063;
|
|
43
48
|
|
|
44
49
|
/**
|
|
45
|
-
* 產生指定空白數量的 CodeToken
|
|
50
|
+
* 產生指定空白數量的 CodeToken,用於縮排、空格等用途。
|
|
46
51
|
*
|
|
47
52
|
* @param count 空白字元數,預設為 1
|
|
48
|
-
* @returns
|
|
53
|
+
* @returns type 為 `"default"`、內容為空格的 `CodeTokenProps`
|
|
49
54
|
*
|
|
50
55
|
* @example
|
|
56
|
+
* ```tsx
|
|
51
57
|
* tokens.push(whiteSpace(2)); // -> { type: "default", children: " " }
|
|
58
|
+
* ```
|
|
52
59
|
*/
|
|
53
60
|
export const whiteSpace = (count: number = 1): CodeTokenProps<"span"> =>
|
|
54
61
|
c063.default(" ".repeat(count));
|
|
55
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 遞迴抽取 ReactNode 中的純文字內容。
|
|
65
|
+
*
|
|
66
|
+
* @param children ReactNode,可以是字串、數字、JSX 元素、陣列等
|
|
67
|
+
* @returns 純文字內容字串
|
|
68
|
+
*/
|
|
69
|
+
const _extractReactNode = (children: React.ReactNode): string => {
|
|
70
|
+
if (typeof children === "string") return children;
|
|
71
|
+
if (typeof children === "number") return children.toString();
|
|
72
|
+
if (Array.isArray(children)) return children.map(_extractReactNode).join("");
|
|
73
|
+
if (React.isValidElement(children)) {
|
|
74
|
+
return _extractReactNode((children as React.JSX.Element).props.children);
|
|
75
|
+
}
|
|
76
|
+
if (typeof children === "object" && children !== null) {
|
|
77
|
+
return React.Children.toArray(children).map(_extractReactNode).join("");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return ""; // 如果 children 是 null 或 undefined,則返回空字串
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 抽取單個 `CodeTokenProps` 的純文字內容。
|
|
85
|
+
*
|
|
86
|
+
* @param token 要處理的 token
|
|
87
|
+
* @returns 對應的文字內容
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```tsx
|
|
91
|
+
* extractTokenContent(c063.keyword1("return")); // => "return"
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
56
94
|
export const extractTokenContent = <T extends React.ElementType>(
|
|
57
95
|
token: CodeTokenProps<T>
|
|
58
96
|
): string => {
|
|
59
|
-
|
|
60
|
-
if (typeof children === "string") return children;
|
|
61
|
-
if (typeof children === "number") return children.toString();
|
|
62
|
-
if (Array.isArray(children)) return children.map(_extract).join("");
|
|
63
|
-
if (React.isValidElement(children)) {
|
|
64
|
-
return _extract((children as React.JSX.Element).props.children);
|
|
65
|
-
}
|
|
66
|
-
return ""; // 如果 children 是 null 或 undefined,則返回空字串
|
|
67
|
-
};
|
|
68
|
-
return _extract(token.children);
|
|
97
|
+
return _extractReactNode(token.children);
|
|
69
98
|
};
|
|
70
99
|
|
|
71
|
-
|
|
100
|
+
/**
|
|
101
|
+
* 判斷兩個 token 是否相等(type 與內容皆相同)。
|
|
102
|
+
*
|
|
103
|
+
* @param a 第一個 token
|
|
104
|
+
* @param b 第二個 token
|
|
105
|
+
* @returns 是否相等
|
|
106
|
+
*/
|
|
107
|
+
export const isTokenEqual = <T extends React.ElementType>(
|
|
108
|
+
a: CodeTokenProps<T>,
|
|
109
|
+
b: CodeTokenProps<T>
|
|
110
|
+
): boolean => {
|
|
111
|
+
return a.type === b.type && extractTokenContent(a) === extractTokenContent(b);
|
|
112
|
+
};
|
|
72
113
|
|
|
114
|
+
/**
|
|
115
|
+
* 將 token 列表按語法類型分類。
|
|
116
|
+
*
|
|
117
|
+
* @param lines 二維陣列,每行為一組 token
|
|
118
|
+
* @returns 分組後的 token 映射,key 為 `CodeTokenType`
|
|
119
|
+
*/
|
|
120
|
+
export const groupTokensByType = <T extends React.ElementType>(
|
|
121
|
+
lines: CodeTokenProps<T>[][]
|
|
122
|
+
): Record<CodeTokenType, CodeTokenProps<T>[]> => {
|
|
123
|
+
const grouped: Record<CodeTokenType, CodeTokenProps<T>[]> = {
|
|
124
|
+
keyword1: [],
|
|
125
|
+
keyword2: [],
|
|
126
|
+
function: [],
|
|
127
|
+
string: [],
|
|
128
|
+
number: [],
|
|
129
|
+
comment: [],
|
|
130
|
+
type: [],
|
|
131
|
+
variable: [],
|
|
132
|
+
constant: [],
|
|
133
|
+
brackets1: [],
|
|
134
|
+
brackets2: [],
|
|
135
|
+
brackets3: [],
|
|
136
|
+
operator: [],
|
|
137
|
+
default: [],
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
for (const token of lines.flat()) {
|
|
141
|
+
grouped[token.type ?? "default"].push(token);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return grouped;
|
|
145
|
+
};
|
|
73
146
|
|
|
74
147
|
/**
|
|
75
|
-
*
|
|
148
|
+
* 待實作
|
|
149
|
+
* `parseTokens` 是語法解析器的代理集合,用來解析特定語言的程式碼字串。
|
|
150
|
+
*
|
|
151
|
+
* 每個 key 對應一種可解析語言(如 `"javascript"`、`"python"` 等),
|
|
152
|
+
* 傳入原始程式碼字串後,回傳解析後的 token 二維陣列(每行一組 token)。
|
|
153
|
+
*
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* const tokens = parseTokens.javascript("const x = 1;");
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @returns 語法高亮用的 `CodeTokenProps` 二維陣列
|
|
76
161
|
*/
|
|
77
|
-
const
|
|
162
|
+
const parseTokens = new Proxy(
|
|
78
163
|
{},
|
|
79
164
|
{
|
|
80
165
|
get: (_, prop: ParsableLanguage) => {
|
|
81
166
|
const parser = (content: string): CodeTokenProps<"span">[][] => {
|
|
82
|
-
|
|
167
|
+
const result: CodeTokenProps<"span">[][] = [];
|
|
168
|
+
|
|
169
|
+
return result;
|
|
83
170
|
};
|
|
84
171
|
return parser;
|
|
85
172
|
},
|