@coffic/cosy-ui 0.6.38 → 0.6.42

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.
@@ -1,6 +1,6 @@
1
1
  import { render, type RenderResult, type CollectionEntry, type DataEntryMap } from 'astro:content';
2
2
  import { SidebarItemEntity, type SidebarProvider } from './SidebarItem';
3
- import { logger } from '../utils/logger';
3
+ import { cosyLogger, ERROR_PREFIX } from '../cosy';
4
4
 
5
5
  /**
6
6
  * 文档基类,提供所有文档类型共享的基本功能
@@ -8,8 +8,7 @@ import { logger } from '../utils/logger';
8
8
  export abstract class BaseDoc<
9
9
  Collection extends keyof DataEntryMap,
10
10
  T extends CollectionEntry<Collection>,
11
- > implements SidebarProvider
12
- {
11
+ > implements SidebarProvider {
13
12
  protected entry: T;
14
13
 
15
14
  constructor(entry: T) {
@@ -54,6 +53,28 @@ export abstract class BaseDoc<
54
53
  */
55
54
  getAncestorId(level: number): string {
56
55
  const ancestorIds = this.getAncestorIds();
56
+
57
+ if (level < 1) {
58
+ cosyLogger.error('Level must be greater than 0');
59
+ throw new Error(ERROR_PREFIX + 'Level must be greater than 0');
60
+ }
61
+
62
+ if (level >= this.getLevel()) {
63
+ cosyLogger.debug("当前文档的ID:" + this.entry.id);
64
+ cosyLogger.debug("当前文档的Level:" + this.getLevel());
65
+ cosyLogger.debug("正在获取祖先ID,level:" + level);
66
+
67
+ throw new Error(ERROR_PREFIX + 'Level must be less than the document level');
68
+ }
69
+
70
+ if (ancestorIds.length < level) {
71
+ cosyLogger.debug("当前文档的ID\n" + this.entry.id);
72
+ cosyLogger.array("当前文档的祖先IDs", ancestorIds);
73
+ cosyLogger.debug("正在获取祖先ID,level:\n" + level);
74
+
75
+ throw new Error(ERROR_PREFIX + 'Level must be greater than 0');
76
+ }
77
+
57
78
  return ancestorIds[level - 1];
58
79
  }
59
80
 
@@ -93,6 +114,12 @@ export abstract class BaseDoc<
93
114
  * 子类可以根据需要覆盖此方法
94
115
  */
95
116
  getTopDocId(): string {
117
+ const level = this.getLevel();
118
+
119
+ if (level <= 2) {
120
+ return this.entry.id;
121
+ }
122
+
96
123
  return this.getAncestorId(2);
97
124
  }
98
125
 
@@ -155,7 +182,7 @@ export abstract class BaseDoc<
155
182
  const childItems = await Promise.all(children.map((child) => child.toSidebarItem()));
156
183
 
157
184
  if (debug) {
158
- logger.info(`${this.entry.id} 的侧边栏项目`);
185
+ cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
159
186
  console.log(childItems);
160
187
  }
161
188
 
@@ -5,6 +5,46 @@ import { BaseDoc } from './BaseDoc';
5
5
  import { COLLECTION_BLOG } from '../database/BlogDB';
6
6
  import { blogDB } from '../database/BlogDB';
7
7
 
8
+ /**
9
+ * 博客文档类,配合 BlogDB 使用
10
+ *
11
+ * 目录结构:
12
+ * ```
13
+ * blogs/
14
+ * ├── zh-cn/ # 中文博客目录
15
+ * │ ├── typescript-intro.md # 文章内容
16
+ * │ ├── images/ # 文章相关图片
17
+ * │ └── web-performance.md
18
+ * └── en/ # 英文博客目录
19
+ * ├── typescript-intro.md
20
+ * ├── images/
21
+ * └── web-performance.md
22
+ * ```
23
+ *
24
+ * 说明:
25
+ * - 每个语言(如 zh-cn, en)是一个独立的目录,存放该语言下的所有博客文章
26
+ * - 每篇博客为一个 markdown 文件,文件名即为 slug
27
+ * - 每个语言目录下可包含 images 文件夹,存放该语言博客相关图片
28
+ * - 支持多语言博客内容,便于国际化
29
+ * - 博客目录可作为 git 子模块独立管理
30
+ *
31
+ * 相关:
32
+ * - BlogDB:博客数据库管理类,负责博客文档的增删查改
33
+ * - BlogDoc:博客文档实体类,封装单篇博客的相关操作
34
+ *
35
+ * 用法示例:
36
+ * ```typescript
37
+ * import BlogDoc from '../entities/BlogDoc';
38
+ * import { blogDB } from '../database/BlogDB';
39
+ *
40
+ * // 获取所有中文博客
41
+ * const blogs = await blogDB.allBlogsByLang('zh-cn');
42
+ *
43
+ * // 获取博客链接
44
+ * const link = blogs[0].getLink();
45
+ * ```
46
+ */
47
+
8
48
  export default class BlogDoc extends BaseDoc<typeof COLLECTION_BLOG, BlogEntry> {
9
49
  private constructor(entry: BlogEntry) {
10
50
  super(entry);
@@ -1,4 +1,4 @@
1
- import { logger } from '../utils/logger';
1
+ import { cosyLogger } from '../cosy';
2
2
  import { SidebarItemEntity } from './SidebarItem';
3
3
  import type { CourseEntry } from '../database/CourseDB';
4
4
  import { courseDB } from '../database/CourseDB';
@@ -36,12 +36,12 @@ export default class CourseDoc extends BaseDoc<typeof COLLECTION_COURSE, CourseE
36
36
  async getAncestor(level: number): Promise<CourseDoc | null> {
37
37
  const debug = false;
38
38
  if (debug) {
39
- logger.info(`获取 ${this.entry.id} 的祖先文档,level: ${level}`);
39
+ cosyLogger.info(`获取 ${this.entry.id} 的祖先文档,level: ${level}`);
40
40
  }
41
41
 
42
42
  if (level >= this.getLevel()) {
43
43
  if (debug) {
44
- logger.info(`祖先文档为自身`);
44
+ cosyLogger.info(`祖先文档为自身`);
45
45
  }
46
46
  return this;
47
47
  }
@@ -61,7 +61,7 @@ export default class CourseDoc extends BaseDoc<typeof COLLECTION_COURSE, CourseE
61
61
  (a, b) => a.getOrder() - b.getOrder()
62
62
  );
63
63
  if (debug && children.length > 0) {
64
- logger.array(
64
+ cosyLogger.array(
65
65
  `${this.entry.id} 的子文档(${children.length})`,
66
66
  children.map((child) => `#${child.getOrder()} ${child.entry.id}`)
67
67
  );
@@ -79,7 +79,7 @@ export default class CourseDoc extends BaseDoc<typeof COLLECTION_COURSE, CourseE
79
79
  }
80
80
 
81
81
  if (debug) {
82
- logger.info(`${this.entry.id} 的侧边栏项目`);
82
+ cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
83
83
  console.log(childItems);
84
84
  }
85
85
 
@@ -1,6 +1,6 @@
1
1
  import type { ExperimentEntry } from '../database/ExperimentDB';
2
2
  import { experimentDB } from '../database/ExperimentDB';
3
- import { logger } from '../utils/logger';
3
+ import { cosyLogger } from '../cosy';
4
4
  import { SidebarItemEntity } from './SidebarItem';
5
5
  import { LinkUtil } from '../utils/link';
6
6
  import { COLLECTION_EXPERIMENT } from '../database/ExperimentDB';
@@ -31,7 +31,7 @@ export default class ExperimentDoc extends BaseDoc<typeof COLLECTION_EXPERIMENT,
31
31
  const link = LinkUtil.getExperimentLink(lang, this.getId());
32
32
 
33
33
  if (debug) {
34
- logger.info(`获取 ${this.entry.id} 的链接: ${link}`);
34
+ cosyLogger.info(`获取 ${this.entry.id} 的链接: ${link}`);
35
35
  }
36
36
 
37
37
  return link;
@@ -51,7 +51,7 @@ export default class ExperimentDoc extends BaseDoc<typeof COLLECTION_EXPERIMENT,
51
51
  const lang = parts[1];
52
52
 
53
53
  if (debug) {
54
- logger.info(`获取 ${this.entry.id} 的语言: ${lang}`);
54
+ cosyLogger.info(`获取 ${this.entry.id} 的语言: ${lang}`);
55
55
  }
56
56
 
57
57
  return lang;
@@ -61,7 +61,7 @@ export default class ExperimentDoc extends BaseDoc<typeof COLLECTION_EXPERIMENT,
61
61
  const debug = false;
62
62
 
63
63
  if (debug) {
64
- logger.info(`获取 ${this.entry.id} 的 HTML`);
64
+ cosyLogger.info(`获取 ${this.entry.id} 的 HTML`);
65
65
  }
66
66
 
67
67
  return this.entry.rendered?.html || '';
@@ -71,7 +71,7 @@ export default class ExperimentDoc extends BaseDoc<typeof COLLECTION_EXPERIMENT,
71
71
  const debug = false;
72
72
 
73
73
  if (debug) {
74
- logger.info(`获取 ${this.entry.id} 的 headings`);
74
+ cosyLogger.info(`获取 ${this.entry.id} 的 headings`);
75
75
  }
76
76
 
77
77
  return (this.entry.rendered?.metadata?.headings as IHeadingType[]) || [];
@@ -101,7 +101,7 @@ export default class ExperimentDoc extends BaseDoc<typeof COLLECTION_EXPERIMENT,
101
101
  }
102
102
 
103
103
  if (debug) {
104
- logger.info(`${this.entry.id} 的侧边栏项目`);
104
+ cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
105
105
  console.log(childItems);
106
106
  }
107
107
 
@@ -1,12 +1,46 @@
1
1
  import type { LessonEntry } from '../database/LessonDB';
2
2
  import { lessonDB } from '../database/LessonDB';
3
- import { logger } from '../utils/logger';
3
+ import { cosyLogger } from '../cosy';
4
4
  import { SidebarItemEntity } from './SidebarItem';
5
5
  import { LinkUtil } from '../utils/link';
6
6
  import { COLLECTION_LESSON } from '../database/LessonDB';
7
7
  import { BaseDoc } from './BaseDoc';
8
8
  import type { IHeadingType } from '../types/heading';
9
9
 
10
+ /**
11
+ * 课程文档类,配合 LessonDB 使用
12
+ *
13
+ * 目录结构:
14
+ * ```
15
+ * lessons/
16
+ * ├── build_your_own_web_toolbox/ # 课程目录
17
+ * │ ├── images/ # 课程图片资源
18
+ * │ ├── components/ # 课程组件
19
+ * │ ├── en/ # 英文版本
20
+ * │ │ ├── index.mdx # 课程首页
21
+ * │ │ ├── 1.mdx # 第一章
22
+ * │ │ └── 2.mdx # 第二章
23
+ * │ └── zh-cn/ # 中文版本
24
+ * │ ├── index.mdx # 课程首页
25
+ * │ ├── 1.mdx # 第一章
26
+ * │ └── 2.mdx # 第二章
27
+ * └── learn_astro/ # 另一个课程
28
+ * ├── en/
29
+ * │ ├── index.mdx
30
+ * │ ├── 1.mdx
31
+ * │ └── 2.mdx
32
+ * └── zh-cn/
33
+ * ├── index.mdx
34
+ * ├── 1.mdx
35
+ * └── 2.mdx
36
+ * ```
37
+ *
38
+ * 说明:
39
+ * - 每个课程(如 build_your_own_web_toolbox)是一个独立的目录
40
+ * - 课程目录可以包含多语言版本(en, zh-cn 等)
41
+ * - 每个语言版本包含完整的课程内容
42
+ * - 课程目录可以作为 git 子模块独立管理
43
+ */
10
44
  export default class LessonDoc extends BaseDoc<typeof COLLECTION_LESSON, LessonEntry> {
11
45
  constructor(entry: LessonEntry) {
12
46
  super(entry);
@@ -31,7 +65,7 @@ export default class LessonDoc extends BaseDoc<typeof COLLECTION_LESSON, LessonE
31
65
  const link = LinkUtil.getLessonLink(lang, this.getId());
32
66
 
33
67
  if (debug) {
34
- logger.info(`获取 ${this.entry.id} 的链接: ${link}`);
68
+ cosyLogger.info(`获取 ${this.entry.id} 的链接: ${link}`);
35
69
  }
36
70
 
37
71
  return link;
@@ -51,7 +85,7 @@ export default class LessonDoc extends BaseDoc<typeof COLLECTION_LESSON, LessonE
51
85
  const lang = parts[1];
52
86
 
53
87
  if (debug) {
54
- logger.info(`获取 ${this.entry.id} 的语言: ${lang}`);
88
+ cosyLogger.info(`获取 ${this.entry.id} 的语言: ${lang}`);
55
89
  }
56
90
 
57
91
  return lang;
@@ -61,7 +95,7 @@ export default class LessonDoc extends BaseDoc<typeof COLLECTION_LESSON, LessonE
61
95
  const debug = false;
62
96
 
63
97
  if (debug) {
64
- logger.info(`获取 ${this.entry.id} 的 HTML`);
98
+ cosyLogger.info(`获取 ${this.entry.id} 的 HTML`);
65
99
  }
66
100
 
67
101
  return this.entry.rendered?.html || '';
@@ -71,7 +105,7 @@ export default class LessonDoc extends BaseDoc<typeof COLLECTION_LESSON, LessonE
71
105
  const debug = false;
72
106
 
73
107
  if (debug) {
74
- logger.info(`获取 ${this.entry.id} 的 headings`);
108
+ cosyLogger.info(`获取 ${this.entry.id} 的 headings`);
75
109
  }
76
110
 
77
111
  return (this.entry.rendered?.metadata?.headings as IHeadingType[]) || [];
@@ -101,7 +135,7 @@ export default class LessonDoc extends BaseDoc<typeof COLLECTION_LESSON, LessonE
101
135
  }
102
136
 
103
137
  if (debug) {
104
- logger.info(`${this.entry.id} 的侧边栏项目`);
138
+ cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
105
139
  console.log(childItems);
106
140
  }
107
141
 
package/dist/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './index_astro';
2
2
  export * from './index_utils';
3
- export * from './index_icons';
3
+ export * from './index_icons';
@@ -202,6 +202,7 @@ const {
202
202
  author={metaConfig.author}
203
203
  robots={metaConfig.robots}
204
204
  head={metaConfig.head}
205
+ favicon={metaConfig.favicon}
205
206
  debug={debug}
206
207
  {...rest}>
207
208
  <ClientRouter />
@@ -50,7 +50,7 @@
50
50
  */
51
51
 
52
52
  import '../style.ts';
53
- import { LinkUtil, type IMetaProps } from '../index';
53
+ import { type IMetaProps } from '../index';
54
54
 
55
55
  export interface Props extends IMetaProps {
56
56
  debug?: boolean;
@@ -66,12 +66,12 @@ const {
66
66
  head,
67
67
  debug = true,
68
68
  class: className,
69
+ favicon,
69
70
  'class:list': classList,
70
71
  } = Astro.props;
71
72
 
72
73
  // 处理类名
73
74
  let bodyClasses = debug ? 'cosy:border cosy:border-red-500' : className || '';
74
- const faviconPath = LinkUtil.createUrl('/favicon.png');
75
75
  ---
76
76
 
77
77
  <!doctype html>
@@ -83,7 +83,7 @@ const faviconPath = LinkUtil.createUrl('/favicon.png');
83
83
  {description && <meta name="description" content={description} />}
84
84
  {keywords && <meta name="keywords" content={keywords} />}
85
85
  <meta name="generator" content={Astro.generator} />
86
- <link rel="icon" type="image/svg+xml" href={faviconPath} />
86
+ {favicon && <link rel="icon" type={favicon.format} href={favicon.src} />}
87
87
 
88
88
  <!-- 自定义样式 -->
89
89
  {customStyles && <style set:html={customStyles} />}
@@ -5,6 +5,11 @@ export interface IMetaProps {
5
5
  author: string;
6
6
  robots: string;
7
7
 
8
+ /**
9
+ * 图标
10
+ */
11
+ favicon?: ImageMetadata;
12
+
8
13
  /**
9
14
  * 基础路径,用于处理网站部署在二级目录的情况
10
15
  * @default ""
@@ -1,16 +1,15 @@
1
- /**
2
- * 语言工具模块
3
- *
4
- * 提供语言相关的工具函数,用于多语言支持
5
- */
6
-
7
1
  import { getRelativeLocaleUrl } from 'astro:i18n';
8
- import { logger } from './logger';
9
2
  import type { AstroGlobal } from 'astro';
3
+ import { cosyLogger } from '../cosy';
10
4
 
11
5
  // 默认语言
12
6
  export const DEFAULT_LANGUAGE = 'en';
13
7
 
8
+ /**
9
+ * 语言工具模块
10
+ *
11
+ * 提供语言相关的工具函数,用于多语言支持
12
+ */
14
13
  export class LanguageUtil {
15
14
  static getRelativeLink(locale: string, astro: AstroGlobal): string {
16
15
  const debug = false;
@@ -19,7 +18,7 @@ export class LanguageUtil {
19
18
  const result = getRelativeLocaleUrl(locale, originalPath.replaceAll('/' + currentLocale, ''));
20
19
 
21
20
  if (debug) {
22
- logger.debug(
21
+ cosyLogger.debug(
23
22
  `getRelativeLink: locale=${locale}, currentPath=${originalPath}, currentLocale=${currentLocale}, result=${result}`
24
23
  );
25
24
  }
@@ -1,4 +1,4 @@
1
- import { logger } from './logger';
1
+ import { cosyLogger } from '../cosy';
2
2
 
3
3
  export class LinkUtil {
4
4
  // 从 astro.config.ts 中获取基础路径
@@ -78,7 +78,7 @@ export class LinkUtil {
78
78
  const blogIdWithoutLang = blogId.replace(`${lang}/`, '');
79
79
 
80
80
  if (debug) {
81
- logger.info(`获取博客文档链接,博客文档ID: ${blogId}`);
81
+ cosyLogger.info(`获取博客文档链接,博客文档ID: ${blogId}`);
82
82
  }
83
83
 
84
84
  return `/${lang}/blogs/${blogIdWithoutLang}`;
@@ -90,7 +90,7 @@ export class LinkUtil {
90
90
  const courseIdWithoutLang = courseId.replace(`${lang}/`, '');
91
91
 
92
92
  if (debug) {
93
- logger.info(`获取课程文档链接,课程文档ID: ${courseId}`);
93
+ cosyLogger.info(`获取课程文档链接,课程文档ID: ${courseId}`);
94
94
  }
95
95
 
96
96
  return LinkUtil.createUrl(`/${lang}/courses/${courseIdWithoutLang}`);
@@ -5,110 +5,126 @@ const SHOW_TIMESTAMP = false;
5
5
 
6
6
  // ANSI 颜色代码
7
7
  const colors = {
8
- reset: '\x1b[0m',
9
- debug: '\x1b[36m', // 青色
10
- info: '\x1b[32m', // 绿色
11
- warn: '\x1b[33m', // 黄色
12
- error: '\x1b[31m', // 红色
13
- gray: '\x1b[90m', // 灰色用于时间戳
8
+ reset: '\x1b[0m',
9
+ debug: '\x1b[36m', // 青色
10
+ info: '\x1b[32m', // 绿色
11
+ warn: '\x1b[33m', // 黄色
12
+ error: '\x1b[31m', // 红色
13
+ gray: '\x1b[90m', // 灰色用于时间戳
14
14
  };
15
15
 
16
- class Logger {
17
- private formatArray(arr: any[]): string {
18
- const MAX_LINES = 70;
19
- const MAX_LENGTH = 100;
20
-
21
- const truncateString = (str: string): string => {
22
- return str.length > MAX_LENGTH ? str.slice(0, MAX_LENGTH) + '...' : str;
23
- };
24
-
25
- const truncateObject = (obj: any): any => {
26
- if (typeof obj !== 'object' || obj === null) {
27
- return typeof obj === 'string' ? truncateString(obj) : obj;
28
- }
29
-
30
- const result: any = Array.isArray(obj) ? [] : {};
31
- for (const [key, value] of Object.entries(obj)) {
32
- result[key] =
33
- typeof value === 'string'
34
- ? truncateString(value)
35
- : typeof value === 'object'
36
- ? truncateObject(value)
37
- : value;
38
- }
39
- return result;
40
- };
41
-
42
- const items = arr.slice(0, MAX_LINES).map((item) => {
43
- const truncatedItem = truncateObject(item);
44
- // 使用2个空格缩进,并在每行前添加 " • "
45
- const jsonString = JSON.stringify(truncatedItem, null, 2)
46
- .split('\n')
47
- .map((line, index) => (index === 0 ? ` • ${line}` : ` ${line}`))
48
- .join('\n');
49
- return jsonString;
50
- });
51
-
52
- let output = items.join('\n');
53
- if (arr.length > MAX_LINES) {
54
- const remainingCount = arr.length - MAX_LINES;
55
- output += `\n ⋮ ... and ${remainingCount} more items`;
56
- }
57
-
58
- return output;
59
- }
60
-
61
- private log(level: LogLevel, message: string | object | any[]) {
62
- // 使用本地时间,并格式化为 HH:mm:ss 格式
63
- const timestamp = new Date().toLocaleTimeString('zh-CN', {
64
- hour12: false,
65
- hour: '2-digit',
66
- minute: '2-digit',
67
- second: '2-digit',
68
- });
69
-
70
- const formattedMessage = Array.isArray(message)
71
- ? this.formatArray(message)
72
- : typeof message === 'object'
73
- ? JSON.stringify(message, null, 2)
74
- : message;
75
-
76
- const timestampPart = SHOW_TIMESTAMP ? `${colors.gray}${timestamp}${colors.reset} ` : '';
77
-
78
- const emoji = {
79
- debug: '🔍',
80
- info: '🐳',
81
- warn: '🚨',
82
- error: '',
83
- }[level];
84
-
85
- console.log(
86
- timestampPart +
87
- `${colors[level]}${emoji} ${level.toUpperCase()}${colors.reset} ` +
88
- `${colors.gray}:${colors.reset} ` +
89
- `${colors[level]}${formattedMessage}${colors.reset}`
90
- );
91
- }
92
-
93
- debug(message: string | object) {
94
- this.log('debug', message);
95
- }
96
-
97
- info(message: string | object) {
98
- this.log('info', message);
99
- }
100
-
101
- warn(message: string | object) {
102
- this.log('warn', message);
103
- }
104
-
105
- error(message: string | object) {
106
- this.log('error', message);
107
- }
108
-
109
- array(title: string, arr: any[]) {
110
- this.log('info', title + '\n' + this.formatArray(arr));
111
- }
16
+ export class Logger {
17
+ private topic: string = '';
18
+
19
+ private formatArray(arr: any[]): string {
20
+ const MAX_LINES = 70;
21
+ const MAX_LENGTH = 100;
22
+
23
+ const truncateString = (str: string): string => {
24
+ return str.length > MAX_LENGTH ? str.slice(0, MAX_LENGTH) + '...' : str;
25
+ };
26
+
27
+ const truncateObject = (obj: any): any => {
28
+ if (typeof obj !== 'object' || obj === null) {
29
+ return typeof obj === 'string' ? truncateString(obj) : obj;
30
+ }
31
+
32
+ const result: any = Array.isArray(obj) ? [] : {};
33
+ for (const [key, value] of Object.entries(obj)) {
34
+ result[key] =
35
+ typeof value === 'string'
36
+ ? truncateString(value)
37
+ : typeof value === 'object'
38
+ ? truncateObject(value)
39
+ : value;
40
+ }
41
+ return result;
42
+ };
43
+
44
+ const items = arr.slice(0, MAX_LINES).map((item) => {
45
+ const truncatedItem = truncateObject(item);
46
+ // 使用2个空格缩进,并在每行前添加 " • "
47
+ const jsonString = JSON.stringify(truncatedItem, null, 2)
48
+ .split('\n')
49
+ .map((line, index) => (index === 0 ? ` • ${line}` : ` ${line}`))
50
+ .join('\n');
51
+ return jsonString;
52
+ });
53
+
54
+ let output = items.join('\n');
55
+ if (arr.length > MAX_LINES) {
56
+ const remainingCount = arr.length - MAX_LINES;
57
+ output += `\n ⋮ ... and ${remainingCount} more items`;
58
+ }
59
+
60
+ return output;
61
+ }
62
+
63
+ private log(level: LogLevel, message: string | object | any[], newLine: boolean = false) {
64
+ // 使用本地时间,并格式化为 HH:mm:ss 格式
65
+ const timestamp = new Date().toLocaleTimeString('zh-CN', {
66
+ hour12: false,
67
+ hour: '2-digit',
68
+ minute: '2-digit',
69
+ second: '2-digit',
70
+ });
71
+
72
+ const formattedMessage = Array.isArray(message)
73
+ ? this.formatArray(message)
74
+ : typeof message === 'object'
75
+ ? JSON.stringify(message, null, 2)
76
+ : message;
77
+
78
+ const timestampPart = SHOW_TIMESTAMP ? `${colors.gray}${timestamp}${colors.reset} ` : '';
79
+
80
+ const emoji = {
81
+ debug: '🔍',
82
+ info: '🐳',
83
+ warn: '🚨',
84
+ error: '❌',
85
+ }[level];
86
+
87
+ if (newLine) {
88
+ console.log("")
89
+ }
90
+
91
+ console.log(
92
+ timestampPart +
93
+ `${colors[level]}${emoji} ` +
94
+ this.getPrefix() +
95
+ `${level.toUpperCase()}${colors.reset} ` +
96
+ `${colors.gray}:${colors.reset} ` +
97
+ `${colors[level]}${formattedMessage}${colors.reset}`
98
+ );
99
+ }
100
+
101
+ private getPrefix() {
102
+ return this.topic ? `[${this.topic}] ` : '';
103
+ }
104
+
105
+ constructor(topic: string = '') {
106
+ this.topic = topic;
107
+ }
108
+
109
+ debug(message: string | object) {
110
+ this.log('debug', message);
111
+ }
112
+
113
+ info(message: string | object) {
114
+ this.log('info', message);
115
+ }
116
+
117
+ warn(message: string | object) {
118
+ this.log('warn', message);
119
+ }
120
+
121
+ error(message: string | object) {
122
+ this.log('error', message, true);
123
+ }
124
+
125
+ array(title: string, arr: any[]) {
126
+ this.log('info', title + '\n' + this.formatArray(arr));
127
+ }
112
128
  }
113
129
 
114
- export const logger = new Logger();
130
+ export const defaultLogger = new Logger();
@@ -1,4 +1,4 @@
1
- import { logger } from './logger';
1
+ import { cosyLogger } from '../cosy';
2
2
 
3
3
  /**
4
4
  * 判断当前路径是否匹配目标路径
@@ -10,13 +10,13 @@ export function isPathMatch(currentPath: string, targetPath: string): boolean {
10
10
  const debug = false;
11
11
 
12
12
  if (debug) {
13
- logger.info(`判断 ${currentPath} 是否匹配 ${targetPath}`);
13
+ cosyLogger.info(`判断 ${currentPath} 是否匹配 ${targetPath}`);
14
14
  }
15
15
 
16
16
  // 如果完全匹配,直接返回
17
17
  if (currentPath === targetPath) {
18
18
  if (debug) {
19
- logger.info(`${currentPath} 完全匹配 ${targetPath}`);
19
+ cosyLogger.info(`${currentPath} 完全匹配 ${targetPath}`);
20
20
  }
21
21
  return true;
22
22
  }