colonynote 0.0.0 → 1.0.0-beta.12
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/LICENSE +21 -0
- package/README.md +125 -0
- package/README.zh.md +125 -0
- package/bin/colonynote.js +148 -0
- package/dist/client/assets/__vite-browser-external-BIHI7g3E.js +1 -0
- package/dist/client/assets/_baseUniq-T-svP185.js +1 -0
- package/dist/client/assets/arc-DPGp6UO-.js +1 -0
- package/dist/client/assets/architectureDiagram-Q4EWVU46-BjON9QCG.js +36 -0
- package/dist/client/assets/blockDiagram-DXYQGD6D-BLoDfE0P.js +132 -0
- package/dist/client/assets/c4Diagram-AHTNJAMY-fQ1soS6G.js +10 -0
- package/dist/client/assets/channel-MqQDOUgw.js +1 -0
- package/dist/client/assets/chunk-4BX2VUAB-BQI2dXlO.js +1 -0
- package/dist/client/assets/chunk-4TB4RGXK-B0FuCAMO.js +206 -0
- package/dist/client/assets/chunk-55IACEB6-SbmoW08H.js +1 -0
- package/dist/client/assets/chunk-EDXVE4YY-BTkJGdcb.js +1 -0
- package/dist/client/assets/chunk-FMBD7UC4-2RG66CzU.js +15 -0
- package/dist/client/assets/chunk-OYMX7WX6-B7irjINX.js +231 -0
- package/dist/client/assets/chunk-QZHKN3VN-rsXCL0TK.js +1 -0
- package/dist/client/assets/chunk-YZCP3GAM-ArKVHPRF.js +1 -0
- package/dist/client/assets/classDiagram-6PBFFD2Q-CZdm6ATq.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-CZdm6ATq.js +1 -0
- package/dist/client/assets/clone-CxH2cmrL.js +1 -0
- package/dist/client/assets/cose-bilkent-S5V4N54A-DVBMSGze.js +1 -0
- package/dist/client/assets/cytoscape.esm-DxGcaOPV.js +331 -0
- package/dist/client/assets/dagre-KV5264BT-COm1avIi.js +4 -0
- package/dist/client/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/client/assets/diagram-5BDNPKRD-BHzIKztM.js +10 -0
- package/dist/client/assets/diagram-G4DWMVQ6-D1JhDGDX.js +24 -0
- package/dist/client/assets/diagram-MMDJMWI5-q28BYReU.js +43 -0
- package/dist/client/assets/diagram-TYMM5635-BoK9AqHX.js +24 -0
- package/dist/client/assets/erDiagram-SMLLAGMA-ogyu4HEv.js +85 -0
- package/dist/client/assets/flowDiagram-DWJPFMVM-DAdHTFWv.js +162 -0
- package/dist/client/assets/ganttDiagram-T4ZO3ILL-DrS8W1v-.js +292 -0
- package/dist/client/assets/gitGraphDiagram-UUTBAWPF-DtK9J5bd.js +106 -0
- package/dist/client/assets/graph-BO_7TUSR.js +1 -0
- package/dist/client/assets/index-BE_qBo7x.js +778 -0
- package/dist/client/assets/index-DpiDy0Bm.css +1 -0
- package/dist/client/assets/infoDiagram-42DDH7IO-C-F87kp2.js +2 -0
- package/dist/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/client/assets/ishikawaDiagram-UXIWVN3A-DpaZPVt0.js +70 -0
- package/dist/client/assets/journeyDiagram-VCZTEJTY-DLdy6qU_.js +139 -0
- package/dist/client/assets/kanban-definition-6JOO6SKY-Cw72R2rP.js +89 -0
- package/dist/client/assets/katex-DkKDou_j.js +257 -0
- package/dist/client/assets/layout-CVdqBmBb.js +1 -0
- package/dist/client/assets/linear-BZWegF8q.js +1 -0
- package/dist/client/assets/min-Bc431PrS.js +1 -0
- package/dist/client/assets/mindmap-definition-QFDTVHPH-DPQMmeL4.js +96 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/client/assets/pieDiagram-DEJITSTG-QjO816qL.js +30 -0
- package/dist/client/assets/quadrantDiagram-34T5L4WZ-BDxYyK8x.js +7 -0
- package/dist/client/assets/requirementDiagram-MS252O5E-CTRbkAm3.js +84 -0
- package/dist/client/assets/sankeyDiagram-XADWPNL6-s1VkzWAg.js +10 -0
- package/dist/client/assets/sequenceDiagram-FGHM5R23-UyatbRZw.js +157 -0
- package/dist/client/assets/stateDiagram-FHFEXIEX-ClKORA1p.js +1 -0
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-Cf33alPP.js +1 -0
- package/dist/client/assets/timeline-definition-GMOUNBTQ-BaJ6GkFx.js +120 -0
- package/dist/client/assets/vennDiagram-DHZGUBPP-C2I2hokK.js +34 -0
- package/dist/client/assets/wardley-RL74JXVD-BaYnW9zG.js +162 -0
- package/dist/client/assets/wardleyDiagram-NUSXRM2D-lI3b3rv0.js +20 -0
- package/dist/client/assets/xychartDiagram-5P7HB3ND-gAPYB-k3.js +7 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/index.html +48 -0
- package/dist/client/logo.png +0 -0
- package/dist/config.js +117 -0
- package/dist/server/api.js +593 -0
- package/dist/server/app.js +21 -0
- package/dist/server/ignore.js +210 -0
- package/dist/server/index.js +116 -0
- package/dist/server/watcher.js +62 -0
- package/package.json +105 -10
- package/index.js +0 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { minimatch } from 'minimatch';
|
|
4
|
+
/**
|
|
5
|
+
* 默认忽略配置
|
|
6
|
+
*/
|
|
7
|
+
export const defaultIgnoreConfig = {
|
|
8
|
+
enableIgnoreFiles: true,
|
|
9
|
+
ignoreFileNames: ['.colonynoteignore', '.gitignore'],
|
|
10
|
+
globalPatterns: [],
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 忽略匹配器 - 管理所有忽略规则并提供匹配功能
|
|
14
|
+
*/
|
|
15
|
+
export class IgnoreMatcher {
|
|
16
|
+
ignoreFiles = new Map();
|
|
17
|
+
globalRules = [];
|
|
18
|
+
rootPath;
|
|
19
|
+
config;
|
|
20
|
+
constructor(rootPath, config = defaultIgnoreConfig) {
|
|
21
|
+
this.rootPath = path.resolve(rootPath);
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.globalRules = this.parsePatterns(config.globalPatterns, this.rootPath);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 解析忽略模式字符串为规则对象
|
|
27
|
+
*/
|
|
28
|
+
parsePatterns(patterns, basePath) {
|
|
29
|
+
const rules = [];
|
|
30
|
+
for (const rawPattern of patterns) {
|
|
31
|
+
// 跳过空行和注释
|
|
32
|
+
const trimmed = rawPattern.trim();
|
|
33
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
34
|
+
continue;
|
|
35
|
+
const isNegation = trimmed.startsWith('!');
|
|
36
|
+
const isDirectory = trimmed.endsWith('/');
|
|
37
|
+
// 处理模式字符串
|
|
38
|
+
let pattern = trimmed;
|
|
39
|
+
// 处理否定模式:移除开头的 !
|
|
40
|
+
if (isNegation) {
|
|
41
|
+
pattern = pattern.slice(1);
|
|
42
|
+
}
|
|
43
|
+
// 处理目录标记:暂时保留,匹配时再处理
|
|
44
|
+
const cleanPattern = isDirectory ? pattern.slice(0, -1) : pattern;
|
|
45
|
+
// 判断是否为绝对路径模式(以 / 开头)
|
|
46
|
+
const isAbsolute = cleanPattern.startsWith('/');
|
|
47
|
+
const rule = {
|
|
48
|
+
pattern: cleanPattern,
|
|
49
|
+
rawPattern: trimmed,
|
|
50
|
+
isNegation,
|
|
51
|
+
isDirectory,
|
|
52
|
+
basePath,
|
|
53
|
+
isAbsolute,
|
|
54
|
+
};
|
|
55
|
+
rules.push(rule);
|
|
56
|
+
}
|
|
57
|
+
return rules;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 加载指定路径的 .ignore 文件
|
|
61
|
+
*/
|
|
62
|
+
loadIgnoreFile(filePath) {
|
|
63
|
+
try {
|
|
64
|
+
if (!fs.existsSync(filePath))
|
|
65
|
+
return false;
|
|
66
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
67
|
+
const lines = content.split(/\r?\n/);
|
|
68
|
+
const basePath = path.dirname(filePath);
|
|
69
|
+
const ignoreFile = {
|
|
70
|
+
filePath,
|
|
71
|
+
basePath,
|
|
72
|
+
rules: this.parsePatterns(lines, basePath),
|
|
73
|
+
};
|
|
74
|
+
this.ignoreFiles.set(filePath, ignoreFile);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error(`Failed to load ignore file ${filePath}:`, e);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 就近查找并加载 .ignore 文件
|
|
84
|
+
* 从 targetPath 向上查找,直到 rootPath
|
|
85
|
+
*/
|
|
86
|
+
findAndLoadIgnoreFiles(targetPath) {
|
|
87
|
+
if (!this.config.enableIgnoreFiles)
|
|
88
|
+
return;
|
|
89
|
+
let currentPath = path.resolve(targetPath);
|
|
90
|
+
// 如果是文件,从其父目录开始查找
|
|
91
|
+
try {
|
|
92
|
+
const stat = fs.statSync(currentPath);
|
|
93
|
+
if (stat.isFile()) {
|
|
94
|
+
currentPath = path.dirname(currentPath);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// 路径不存在,假设是目录
|
|
99
|
+
}
|
|
100
|
+
while (currentPath.startsWith(this.rootPath) && currentPath.length >= this.rootPath.length) {
|
|
101
|
+
for (const fileName of this.config.ignoreFileNames) {
|
|
102
|
+
const ignoreFilePath = path.join(currentPath, fileName);
|
|
103
|
+
// 避免重复加载
|
|
104
|
+
if (!this.ignoreFiles.has(ignoreFilePath)) {
|
|
105
|
+
this.loadIgnoreFile(ignoreFilePath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// 向上一级目录
|
|
109
|
+
const parentPath = path.dirname(currentPath);
|
|
110
|
+
if (parentPath === currentPath)
|
|
111
|
+
break; // 已到达根目录
|
|
112
|
+
currentPath = parentPath;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 检查单个规则是否匹配目标路径
|
|
117
|
+
*/
|
|
118
|
+
matchRule(rule, targetPath, isDirectory) {
|
|
119
|
+
const relativePath = path.relative(rule.basePath, targetPath);
|
|
120
|
+
if (rule.isAbsolute) {
|
|
121
|
+
const patternWithoutSlash = rule.pattern.replace(/^\//, '');
|
|
122
|
+
if (relativePath === patternWithoutSlash ||
|
|
123
|
+
relativePath.startsWith(patternWithoutSlash + path.sep)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
return minimatch(relativePath, patternWithoutSlash, { dot: true });
|
|
127
|
+
}
|
|
128
|
+
if (!rule.pattern.includes('/')) {
|
|
129
|
+
const basename = path.basename(targetPath);
|
|
130
|
+
if (rule.isDirectory) {
|
|
131
|
+
if (minimatch(basename, rule.pattern, { dot: true })) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
const parts = relativePath.split(path.sep);
|
|
135
|
+
for (let i = 0; i < parts.length; i++) {
|
|
136
|
+
if (minimatch(parts[i], rule.pattern, { dot: true })) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
if (minimatch(basename, rule.pattern, { dot: true })) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return minimatch(relativePath, rule.pattern, { dot: true });
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 检查路径是否被忽略
|
|
152
|
+
* 返回 true 表示应该忽略,false 表示不忽略
|
|
153
|
+
*/
|
|
154
|
+
isIgnored(targetPath, isDirectory = false) {
|
|
155
|
+
const absolutePath = path.resolve(targetPath);
|
|
156
|
+
// 确保路径在 root 内
|
|
157
|
+
if (!absolutePath.startsWith(this.rootPath))
|
|
158
|
+
return false;
|
|
159
|
+
// 就近查找并加载 .ignore 文件
|
|
160
|
+
this.findAndLoadIgnoreFiles(absolutePath);
|
|
161
|
+
// 收集所有相关规则(按优先级排序)
|
|
162
|
+
// 规则优先级:就近的 .ignore 文件 > 上层的 .ignore 文件 > 全局配置
|
|
163
|
+
const allRules = [];
|
|
164
|
+
// 1. 添加全局规则(最低优先级)
|
|
165
|
+
allRules.push(...this.globalRules);
|
|
166
|
+
// 2. 添加 .ignore 文件规则(按目录层级从根到当前)
|
|
167
|
+
const sortedIgnoreFiles = Array.from(this.ignoreFiles.values())
|
|
168
|
+
.sort((a, b) => {
|
|
169
|
+
// 按 basePath 深度排序:根目录优先级低,近目录优先级高
|
|
170
|
+
const depthA = a.basePath.split(path.sep).length;
|
|
171
|
+
const depthB = b.basePath.split(path.sep).length;
|
|
172
|
+
return depthA - depthB;
|
|
173
|
+
});
|
|
174
|
+
for (const ignoreFile of sortedIgnoreFiles) {
|
|
175
|
+
// 只考虑影响当前路径的规则文件
|
|
176
|
+
if (absolutePath.startsWith(ignoreFile.basePath)) {
|
|
177
|
+
allRules.push(...ignoreFile.rules);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// 3. 应用规则(后出现的规则优先级更高)
|
|
181
|
+
let shouldIgnore = false;
|
|
182
|
+
for (const rule of allRules) {
|
|
183
|
+
if (this.matchRule(rule, absolutePath, isDirectory)) {
|
|
184
|
+
// 否定规则取消忽略
|
|
185
|
+
if (rule.isNegation) {
|
|
186
|
+
shouldIgnore = false;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
shouldIgnore = true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return shouldIgnore;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 清除缓存的 .ignore 文件(用于重新加载)
|
|
197
|
+
*/
|
|
198
|
+
clearCache() {
|
|
199
|
+
this.ignoreFiles.clear();
|
|
200
|
+
}
|
|
201
|
+
updateGlobalPatterns(patterns) {
|
|
202
|
+
this.globalRules = this.parsePatterns(patterns, this.rootPath);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 获取已加载的 .ignore 文件列表
|
|
206
|
+
*/
|
|
207
|
+
getLoadedIgnoreFiles() {
|
|
208
|
+
return Array.from(this.ignoreFiles.keys());
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { serve } from '@hono/node-server';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { cors } from 'hono/cors';
|
|
4
|
+
import { createFileRouter } from './api.js';
|
|
5
|
+
import { loadConfig, DEFAULT_PORT, DEFAULT_HOST } from '../config.js';
|
|
6
|
+
import { setupWatcher } from './watcher.js';
|
|
7
|
+
import { IgnoreMatcher } from './ignore.js';
|
|
8
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const clientDir = path.join(__dirname, '..', 'client');
|
|
14
|
+
function findRootForPath(filePath, config) {
|
|
15
|
+
for (const root of config.roots) {
|
|
16
|
+
if (filePath.startsWith(root.path)) {
|
|
17
|
+
return root.path;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return config.roots[0]?.path || '';
|
|
21
|
+
}
|
|
22
|
+
async function main() {
|
|
23
|
+
const config = await loadConfig();
|
|
24
|
+
const matcher = new IgnoreMatcher(config.roots[0]?.path || process.cwd(), {
|
|
25
|
+
enableIgnoreFiles: config.ignore.enableIgnoreFiles,
|
|
26
|
+
ignoreFileNames: config.ignore.ignoreFileNames,
|
|
27
|
+
globalPatterns: config.ignore.patterns,
|
|
28
|
+
});
|
|
29
|
+
const app = new Hono();
|
|
30
|
+
app.use('*', cors());
|
|
31
|
+
const fileRouter = createFileRouter(config, matcher);
|
|
32
|
+
app.route('/api/files', fileRouter);
|
|
33
|
+
app.get('/assets/*', async (c) => {
|
|
34
|
+
const filePath = c.req.path.replace('/assets', '');
|
|
35
|
+
const fullPath = path.join(clientDir, 'assets', filePath);
|
|
36
|
+
try {
|
|
37
|
+
const content = fs.readFileSync(fullPath);
|
|
38
|
+
const ext = path.extname(filePath);
|
|
39
|
+
const contentType = ext === '.js' ? 'application/javascript' : ext === '.css' ? 'text/css' : 'text/plain';
|
|
40
|
+
return new Response(content, { headers: { 'Content-Type': contentType } });
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return c.notFound();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
app.get('/logo.png', async (c) => {
|
|
47
|
+
const fullPath = path.join(clientDir, 'logo.png');
|
|
48
|
+
try {
|
|
49
|
+
const content = fs.readFileSync(fullPath);
|
|
50
|
+
return new Response(content, { headers: { 'Content-Type': 'image/png' } });
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return c.notFound();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
app.get('/favicon.ico', async (c) => {
|
|
57
|
+
const fullPath = path.join(clientDir, 'favicon.ico');
|
|
58
|
+
try {
|
|
59
|
+
const content = fs.readFileSync(fullPath);
|
|
60
|
+
return new Response(content, { headers: { 'Content-Type': 'image/x-icon' } });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return c.notFound();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
app.get('*', async (c) => {
|
|
67
|
+
const indexPath = path.join(clientDir, 'index.html');
|
|
68
|
+
try {
|
|
69
|
+
const content = fs.readFileSync(indexPath, 'utf-8');
|
|
70
|
+
return new Response(content, {
|
|
71
|
+
headers: { 'Content-Type': 'text/html' },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return c.notFound();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
const server = serve({
|
|
79
|
+
fetch: app.fetch,
|
|
80
|
+
port: DEFAULT_PORT,
|
|
81
|
+
hostname: DEFAULT_HOST,
|
|
82
|
+
});
|
|
83
|
+
const clients = new Set();
|
|
84
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
85
|
+
wss.on('connection', (ws) => {
|
|
86
|
+
clients.add(ws);
|
|
87
|
+
ws.on('close', () => clients.delete(ws));
|
|
88
|
+
});
|
|
89
|
+
server.on('upgrade', (request, socket, head) => {
|
|
90
|
+
if (request.url === '/ws') {
|
|
91
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
92
|
+
wss.emit('connection', ws, request);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
setupWatcher(config, matcher, {
|
|
97
|
+
onFileChange: (rootPath, event, filePath) => {
|
|
98
|
+
const actualRootPath = findRootForPath(filePath, config);
|
|
99
|
+
const relativePath = filePath.replace(actualRootPath, '');
|
|
100
|
+
const message = JSON.stringify({ type: 'file:change', event, path: relativePath, rootPath: actualRootPath });
|
|
101
|
+
clients.forEach((client) => {
|
|
102
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
103
|
+
client.send(message);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
console.log(`\n ColonyNote is running!\n`);
|
|
109
|
+
console.log(` Local: http://localhost:${DEFAULT_PORT}`);
|
|
110
|
+
console.log(` Network: http://${DEFAULT_HOST}:${DEFAULT_PORT}`);
|
|
111
|
+
console.log(` Roots: ${config.roots.map(r => r.path).join(', ')}\n`);
|
|
112
|
+
}
|
|
113
|
+
main().catch((e) => {
|
|
114
|
+
console.error('Failed to start:', e);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
export function setupWatcher(config, matcher, callbacks) {
|
|
4
|
+
const rootPaths = config.roots.map(r => r.path);
|
|
5
|
+
const watcher = chokidar.watch(rootPaths, {
|
|
6
|
+
ignored: (filePath) => {
|
|
7
|
+
if (!config.showHiddenFiles && (filePath.includes('/.') || filePath.startsWith('.')))
|
|
8
|
+
return true;
|
|
9
|
+
try {
|
|
10
|
+
const stat = fs.statSync(filePath);
|
|
11
|
+
if (matcher.isIgnored(filePath, stat.isDirectory()))
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
if (matcher.isIgnored(filePath, false))
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
const ext = filePath.split('.').pop()?.toLowerCase() || '';
|
|
19
|
+
if (ext && !config.allowedExtensions.includes('.' + ext) && !filePath.includes('/')) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
},
|
|
24
|
+
persistent: true,
|
|
25
|
+
ignoreInitial: true,
|
|
26
|
+
depth: 3,
|
|
27
|
+
});
|
|
28
|
+
watcher
|
|
29
|
+
.on('add', (path) => {
|
|
30
|
+
if (config.allowedExtensions.some(ext => path.endsWith(ext))) {
|
|
31
|
+
const matchingRoot = config.roots.find(r => path.startsWith(r.path));
|
|
32
|
+
const rootPath = matchingRoot?.path || config.roots[0]?.path || '';
|
|
33
|
+
callbacks.onFileChange(rootPath, 'add', path);
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
.on('change', (path) => {
|
|
37
|
+
if (config.allowedExtensions.some(ext => path.endsWith(ext))) {
|
|
38
|
+
const matchingRoot = config.roots.find(r => path.startsWith(r.path));
|
|
39
|
+
const rootPath = matchingRoot?.path || config.roots[0]?.path || '';
|
|
40
|
+
callbacks.onFileChange(rootPath, 'change', path);
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
.on('unlink', (path) => {
|
|
44
|
+
if (config.allowedExtensions.some(ext => path.endsWith(ext))) {
|
|
45
|
+
const matchingRoot = config.roots.find(r => path.startsWith(r.path));
|
|
46
|
+
const rootPath = matchingRoot?.path || config.roots[0]?.path || '';
|
|
47
|
+
callbacks.onFileChange(rootPath, 'unlink', path);
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
.on('addDir', (path) => {
|
|
51
|
+
const matchingRoot = config.roots.find(r => path.startsWith(r.path));
|
|
52
|
+
const rootPath = matchingRoot?.path || config.roots[0]?.path || '';
|
|
53
|
+
callbacks.onFileChange(rootPath, 'addDir', path);
|
|
54
|
+
})
|
|
55
|
+
.on('unlinkDir', (path) => {
|
|
56
|
+
const matchingRoot = config.roots.find(r => path.startsWith(r.path));
|
|
57
|
+
const rootPath = matchingRoot?.path || config.roots[0]?.path || '';
|
|
58
|
+
callbacks.onFileChange(rootPath, 'unlinkDir', path);
|
|
59
|
+
})
|
|
60
|
+
.on('error', (error) => console.error('Watcher error:', error));
|
|
61
|
+
return watcher;
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,108 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "colonynote",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=18"
|
|
6
|
+
},
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"description": "Markdown online editor with real-time preview and LaTeX support",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"markdown",
|
|
11
|
+
"editor",
|
|
12
|
+
"latex",
|
|
13
|
+
"real-time",
|
|
14
|
+
"cli",
|
|
15
|
+
"document"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "岳晓亮 <hi@yuexiaoliang.com>",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/opencolony/note.git"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"colonynote": "./bin/colonynote.js"
|
|
8
29
|
},
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
30
|
+
"files": [
|
|
31
|
+
"bin",
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@hono/node-server": "^1.19.11",
|
|
36
|
+
"@milkdown/crepe": "^7.19.2",
|
|
37
|
+
"@milkdown/plugin-listener": "^7.19.2",
|
|
38
|
+
"@milkdown/prose": "^7.19.2",
|
|
39
|
+
"@milkdown/react": "^7.19.2",
|
|
40
|
+
"@milkdown/utils": "^7.19.2",
|
|
41
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
42
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
43
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
44
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
45
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
46
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
47
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
48
|
+
"@tailwindcss/vite": "^4.2.2",
|
|
49
|
+
"@tiptap/extension-code-block-lowlight": "^3.20.4",
|
|
50
|
+
"@tiptap/extension-highlight": "^3.20.4",
|
|
51
|
+
"@tiptap/extension-image": "^3.20.4",
|
|
52
|
+
"@tiptap/extension-link": "^3.20.4",
|
|
53
|
+
"@tiptap/extension-placeholder": "^3.20.4",
|
|
54
|
+
"@tiptap/extension-table": "^3.20.4",
|
|
55
|
+
"@tiptap/extension-table-cell": "^3.20.4",
|
|
56
|
+
"@tiptap/extension-table-header": "^3.20.4",
|
|
57
|
+
"@tiptap/extension-table-row": "^3.20.4",
|
|
58
|
+
"@tiptap/extension-task-item": "^3.20.4",
|
|
59
|
+
"@tiptap/extension-task-list": "^3.20.4",
|
|
60
|
+
"@tiptap/extension-typography": "^3.20.4",
|
|
61
|
+
"@tiptap/extension-underline": "^3.20.4",
|
|
62
|
+
"@tiptap/pm": "^3.20.4",
|
|
63
|
+
"@tiptap/react": "^3.20.4",
|
|
64
|
+
"@tiptap/starter-kit": "^3.20.4",
|
|
65
|
+
"chokidar": "^4.0.3",
|
|
66
|
+
"class-variance-authority": "^0.7.1",
|
|
67
|
+
"clsx": "^2.1.1",
|
|
68
|
+
"cmdk": "^1.1.1",
|
|
69
|
+
"colonynote": "1.0.0-beta.10",
|
|
70
|
+
"commander": "^14.0.3",
|
|
71
|
+
"flexsearch": "^0.8.212",
|
|
72
|
+
"hono": "^4.12.9",
|
|
73
|
+
"katex": "^0.16.40",
|
|
74
|
+
"lowlight": "^3.3.0",
|
|
75
|
+
"lucide-react": "^0.577.0",
|
|
76
|
+
"markdown-extensions": "^2.0.0",
|
|
77
|
+
"mermaid": "^11.13.0",
|
|
78
|
+
"minimatch": "^10.2.5",
|
|
79
|
+
"react": "^18.3.1",
|
|
80
|
+
"react-dom": "^18.3.1",
|
|
81
|
+
"react-zoom-pan-pinch": "^3.7.0",
|
|
82
|
+
"tailwind-merge": "^3.5.0",
|
|
83
|
+
"tailwindcss": "^4.2.2",
|
|
84
|
+
"tiptap-markdown": "^0.9.0",
|
|
85
|
+
"ws": "^8.20.0"
|
|
86
|
+
},
|
|
87
|
+
"devDependencies": {
|
|
88
|
+
"@types/node": "^22.19.15",
|
|
89
|
+
"@types/react": "^18.3.28",
|
|
90
|
+
"@types/react-dom": "^18.3.7",
|
|
91
|
+
"@types/ws": "^8.18.1",
|
|
92
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
93
|
+
"bumpp": "^11.0.1",
|
|
94
|
+
"tsx": "^4.21.0",
|
|
95
|
+
"typescript": "^5.9.3",
|
|
96
|
+
"vite": "^6.4.1"
|
|
97
|
+
},
|
|
98
|
+
"scripts": {
|
|
99
|
+
"dev": "tsx src/dev.ts",
|
|
100
|
+
"dev:frontend": "vite",
|
|
101
|
+
"dev:backend": "tsx src/server/index.ts",
|
|
102
|
+
"build": "vite build && tsc -p tsconfig.server.json",
|
|
103
|
+
"preview": "vite preview",
|
|
104
|
+
"start": "node dist/server/index.js",
|
|
105
|
+
"typecheck": "tsc --noEmit",
|
|
106
|
+
"release": "bumpp"
|
|
107
|
+
}
|
|
108
|
+
}
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
console.log('hello')
|