wendang 0.1.0 → 0.2.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/LICENSE +43 -2
- package/NOTICE.md +1 -1
- package/README.md +120 -52
- package/dist/cjs/document.js +1 -19
- package/dist/cjs/index.js +1 -25
- package/dist/cjs/mindmap.js +1 -22
- package/dist/cjs/schema.js +1 -11
- package/dist/cjs/shared/anchor.js +1 -201
- package/dist/cjs/shared/callout.js +1 -64
- package/dist/cjs/shared/code-block.js +1 -33
- package/dist/cjs/shared/code-languages.js +1 -51
- package/dist/cjs/shared/doc-compatibility.js +1 -23
- package/dist/cjs/shared/doc-text.js +1 -52
- package/dist/cjs/shared/document-colors.js +1 -61
- package/dist/cjs/shared/headings.js +1 -0
- package/dist/cjs/shared/inline-comments.js +1 -179
- package/dist/cjs/shared/mind-map-folding.js +1 -14
- package/dist/cjs/shared/mind-map-phase2.js +1 -133
- package/dist/cjs/shared/mind-map.js +1 -445
- package/dist/cjs/shared/mind-topic-text.js +1 -57
- package/dist/cjs/shared/node-catalog.js +1 -62
- package/dist/cjs/shared/presence.js +1 -141
- package/dist/cjs/shared/safe-href.js +1 -36
- package/dist/cjs/shared/table-cell-format.js +1 -18
- package/dist/cjs/shared/table-layout.js +1 -28
- package/dist/cjs/shared/types.js +1 -2
- package/dist/cjs/shared/video-embed.js +1 -102
- package/dist/cjs/shared/workbook.js +1 -152
- package/dist/cjs/spreadsheet.js +1 -17
- package/dist/cjs/types.js +1 -17
- package/dist/cjs/validation/callout.js +1 -17
- package/dist/cjs/validation/doc-node-whitelist.js +1 -71
- package/dist/cjs/validation/error.js +1 -17
- package/dist/cjs/validation/mind-map.js +1 -129
- package/dist/cjs/validation/schema-version.js +1 -5
- package/dist/cjs/validation/schema.js +1 -376
- package/dist/cjs/validation/video-embed.js +1 -17
- package/dist/cjs/validation/workbook.js +1 -17
- package/dist/esm/document.js +1 -3
- package/dist/esm/index.js +1 -3
- package/dist/esm/mindmap.js +1 -4
- package/dist/esm/schema.js +1 -3
- package/dist/esm/shared/anchor.js +1 -192
- package/dist/esm/shared/callout.js +1 -56
- package/dist/esm/shared/code-block.js +1 -25
- package/dist/esm/shared/code-languages.js +1 -46
- package/dist/esm/shared/doc-compatibility.js +1 -20
- package/dist/esm/shared/doc-text.js +1 -48
- package/dist/esm/shared/document-colors.js +1 -56
- package/dist/esm/shared/headings.js +1 -0
- package/dist/esm/shared/inline-comments.js +1 -173
- package/dist/esm/shared/mind-map-folding.js +1 -10
- package/dist/esm/shared/mind-map-phase2.js +1 -121
- package/dist/esm/shared/mind-map.js +1 -427
- package/dist/esm/shared/mind-topic-text.js +1 -49
- package/dist/esm/shared/node-catalog.js +1 -57
- package/dist/esm/shared/presence.js +1 -130
- package/dist/esm/shared/safe-href.js +1 -32
- package/dist/esm/shared/table-cell-format.js +1 -14
- package/dist/esm/shared/table-layout.js +1 -23
- package/dist/esm/shared/types.js +1 -1
- package/dist/esm/shared/video-embed.js +1 -96
- package/dist/esm/shared/workbook.js +1 -144
- package/dist/esm/spreadsheet.js +1 -1
- package/dist/esm/types.js +1 -1
- package/dist/esm/validation/callout.js +1 -1
- package/dist/esm/validation/doc-node-whitelist.js +1 -68
- package/dist/esm/validation/error.js +1 -13
- package/dist/esm/validation/mind-map.js +1 -125
- package/dist/esm/validation/schema-version.js +1 -2
- package/dist/esm/validation/schema.js +1 -372
- package/dist/esm/validation/video-embed.js +1 -1
- package/dist/esm/validation/workbook.js +1 -1
- package/dist/types/document.d.ts +1 -0
- package/dist/types/shared/anchor.d.ts +0 -55
- package/dist/types/shared/callout.d.ts +39 -2
- package/dist/types/shared/code-block.d.ts +0 -1
- package/dist/types/shared/code-languages.d.ts +0 -19
- package/dist/types/shared/doc-text.d.ts +0 -14
- package/dist/types/shared/document-colors.d.ts +0 -4
- package/dist/types/shared/headings.d.ts +7 -0
- package/dist/types/shared/inline-comments.d.ts +0 -42
- package/dist/types/shared/mind-map-folding.d.ts +0 -2
- package/dist/types/shared/mind-map.d.ts +0 -4
- package/dist/types/shared/mind-topic-text.d.ts +0 -2
- package/dist/types/shared/node-catalog.d.ts +0 -17
- package/dist/types/shared/presence.d.ts +0 -51
- package/dist/types/shared/safe-href.d.ts +0 -1
- package/dist/types/shared/table-cell-format.d.ts +0 -1
- package/dist/types/shared/table-layout.d.ts +0 -3
- package/dist/types/shared/types.d.ts +0 -4
- package/dist/types/shared/video-embed.d.ts +9 -2
- package/dist/types/shared/workbook.d.ts +0 -2
- package/dist/types/validation/doc-node-whitelist.d.ts +0 -19
- package/dist/types/validation/mind-map.d.ts +0 -2
- package/dist/types/validation/schema-version.d.ts +0 -1
- package/dist/types/validation/schema.d.ts +0 -34
- package/package.json +9 -9
package/LICENSE
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
Wendang 商业使用许可 1.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Copyright (c) 2026 ztes. All rights reserved.
|
|
4
|
+
|
|
5
|
+
本许可适用于 Wendang 项目及 wendang、wendang-vue 包中由 ztes 拥有版权的代码。
|
|
6
|
+
使用、复制或分发本软件即表示接受以下条款。
|
|
7
|
+
|
|
8
|
+
1. 允许的使用
|
|
9
|
+
在遵守本许可的前提下,授予您非独占、全球、免许可费的权利:
|
|
10
|
+
a. 将本软件用于个人、内部或商业用途,包括收费产品、客户项目及 SaaS 服务;
|
|
11
|
+
b. 为开发、集成、测试、维护和运行您的应用而复制本软件,并修改源码;
|
|
12
|
+
c. 将原版或修改后的编译代码作为您的应用组成部分交付给客户或最终用户,
|
|
13
|
+
包括网站、浏览器应用、桌面应用、移动应用及服务端部署;
|
|
14
|
+
d. 向受保密义务约束的雇员、承包商或客户提供维护上述应用所需的源码,
|
|
15
|
+
前提是这些接收者只能为该应用使用源码并遵守本许可。
|
|
16
|
+
您无需公开应用源码,也无需向 ztes 支付商业使用许可费。
|
|
17
|
+
|
|
18
|
+
2. 限制及保留的权利
|
|
19
|
+
本许可未授予您将本软件或其修改版作为独立库、SDK、编辑器组件包或源码
|
|
20
|
+
产品进行公开再发布、再许可、改名发布、出售或出租的权利。
|
|
21
|
+
上述限制不妨碍您销售或运营包含本软件的应用,也不妨碍按第 1 条交付应用。
|
|
22
|
+
超出本许可范围的独立分发或源码再许可,须另获 ztes 书面授权。
|
|
23
|
+
不得移除本软件中的版权、许可及第三方权利声明。本许可不授予商标权;
|
|
24
|
+
其他未明确授予的权利由各权利人保留。
|
|
25
|
+
|
|
26
|
+
3. 声明的保留
|
|
27
|
+
分发包含本软件的应用时,应在随附许可文件、第三方声明或应用关于页面中
|
|
28
|
+
保留本许可及版权声明。无需在应用主界面展示品牌或链接。
|
|
29
|
+
|
|
30
|
+
4. 第三方组件
|
|
31
|
+
第三方组件及其版权声明继续适用各自许可证,见 NOTICE.md 和
|
|
32
|
+
third-party-notices/。本许可不限制第三方许可证已经授予的权利。
|
|
33
|
+
|
|
34
|
+
5. 终止
|
|
35
|
+
如违反本许可且未在收到书面通知后 30 日内纠正,本许可授予的权利终止。
|
|
36
|
+
终止不影响终止前已产生的义务及权利人的救济权。
|
|
37
|
+
|
|
38
|
+
6. 免责声明与责任限制
|
|
39
|
+
在适用法律允许的最大范围内,本软件按“现状”提供,不附带任何明示或
|
|
40
|
+
默示担保,包括适销性、特定用途适用性及不侵权担保。对于使用或无法使用
|
|
41
|
+
本软件产生的损害、数据丢失、利润损失或其他责任,作者及权利人不承担责任。
|
|
42
|
+
|
|
43
|
+
这是保留源码权利的商业使用许可,不是开源许可证。
|
|
44
|
+
授权联系:https://doc.yjmf.com
|
package/NOTICE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
3
|
Generated from the installed runtime dependency graph; package licenses remain unchanged.
|
|
4
|
-
Wendang
|
|
4
|
+
Wendang is licensed under the Wendang Commercial Use License; see LICENSE. Third-party components retain their own licenses.
|
|
5
5
|
|
|
6
6
|
| Package | Version | Declared license | Included upstream notice |
|
|
7
7
|
| --- | --- | --- | --- |
|
package/README.md
CHANGED
|
@@ -1,104 +1,172 @@
|
|
|
1
1
|
# wendang
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
文档、电子表格和思维导图的内容协议与校验核心,适用于浏览器数据层和 Node.js 服务端。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[主页](https://doc.yjmf.com) · [Vue 编辑组件](https://www.npmjs.com/package/wendang-vue)
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
对应版本正式发布后:
|
|
7
|
+
## 安装
|
|
10
8
|
|
|
11
9
|
```sh
|
|
12
10
|
npm install wendang
|
|
13
11
|
```
|
|
14
12
|
|
|
13
|
+
支持 Node.js >=20.19、ESM、CommonJS 和 TypeScript。无运行时依赖,不初始化 DOM,也不发起网络请求。
|
|
14
|
+
|
|
15
|
+
## 文档校验
|
|
16
|
+
|
|
15
17
|
```ts
|
|
16
18
|
import { ContentSchemaService, SCHEMA_VERSION } from 'wendang/schema'
|
|
17
|
-
import {
|
|
18
|
-
import { createMindMap, readMindMap, mindMapToJson } from 'wendang/mindmap'
|
|
19
|
-
import type { ProseMirrorDoc, WorkbookDocument } from 'wendang/types'
|
|
19
|
+
import type { ProseMirrorDoc } from 'wendang/types'
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const doc: ProseMirrorDoc = {
|
|
22
22
|
type: 'doc',
|
|
23
|
-
content: [{
|
|
24
|
-
|
|
23
|
+
content: [{
|
|
24
|
+
type: 'paragraph',
|
|
25
|
+
content: [{ type: 'text', text: '你好,Wendang' }],
|
|
26
|
+
}],
|
|
27
|
+
}
|
|
25
28
|
|
|
26
|
-
const
|
|
27
|
-
|
|
29
|
+
const result = new ContentSchemaService().validate(doc, SCHEMA_VERSION)
|
|
30
|
+
console.log(result.doc)
|
|
31
|
+
console.log(result.attachmentIds)
|
|
32
|
+
console.log(result.linkTargetIds)
|
|
33
|
+
console.log(result.mentionUserIds)
|
|
28
34
|
```
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
CommonJS:
|
|
31
37
|
|
|
32
38
|
```js
|
|
33
39
|
const { ContentSchemaService, SCHEMA_VERSION } = require('wendang/schema')
|
|
40
|
+
|
|
34
41
|
const result = new ContentSchemaService().validate(
|
|
35
42
|
{ type: 'doc', content: [{ type: 'paragraph' }] },
|
|
36
43
|
SCHEMA_VERSION,
|
|
37
44
|
)
|
|
38
45
|
```
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
## API 入口
|
|
47
|
+
`validate(raw, schemaVersion)` 返回以下字段:
|
|
43
48
|
|
|
44
|
-
|
|
|
49
|
+
| 字段 | 含义 |
|
|
45
50
|
| --- | --- |
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `wendang/types` | 内容、工作簿、导图和讨论类型 |
|
|
51
|
+
| `doc` | 校验并按白名单处理后的内容 |
|
|
52
|
+
| `schemaVersion` | 内容 schema 版本 |
|
|
53
|
+
| `attachmentIds` | 附件 ID 列表 |
|
|
54
|
+
| `linkTargetIds` | 被引用页面的 ID 列表 |
|
|
55
|
+
| `mentionUserIds` | 被提及用户的 ID 列表 |
|
|
52
56
|
|
|
53
|
-
`
|
|
57
|
+
未知节点、非法值和不支持的更高版本会被拒绝。`schemaVersion` 必须为正整数;普通文档当前版本为 `10`。
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
### 处理校验错误
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
```ts
|
|
62
|
+
import {
|
|
63
|
+
ContentSchemaService,
|
|
64
|
+
ContentValidationError,
|
|
65
|
+
SCHEMA_VERSION,
|
|
66
|
+
} from 'wendang/schema'
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
new ContentSchemaService().validate({ type: 'unknown' }, SCHEMA_VERSION)
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (error instanceof ContentValidationError) {
|
|
72
|
+
console.error(error.code, error.message, error.details)
|
|
73
|
+
} else {
|
|
74
|
+
throw error
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
63
78
|
|
|
64
|
-
|
|
79
|
+
`ContentValidationError` 包含 `code`、`message`、`status` 和可选 `details`。普通校验错误的 `code` 为 `validation.failed`,`status` 为 `422`;可由应用映射成 HTTP 响应。
|
|
65
80
|
|
|
66
|
-
|
|
81
|
+
内容校验不执行授权。服务端仍需检查写入权限、附件归属和引用资源可见性。页面、用户、附件引用使用 UUID;其他业务主键需建立稳定映射。
|
|
67
82
|
|
|
68
|
-
##
|
|
83
|
+
## 电子表格
|
|
69
84
|
|
|
70
85
|
```ts
|
|
86
|
+
import {
|
|
87
|
+
emptyWorkbook,
|
|
88
|
+
validateWorkbook,
|
|
89
|
+
workbookText,
|
|
90
|
+
} from 'wendang/spreadsheet'
|
|
91
|
+
|
|
71
92
|
const doc = emptyWorkbook(crypto.randomUUID())
|
|
93
|
+
doc.workbook.name = '销售统计'
|
|
72
94
|
doc.workbook.sheets.sheet1.cellData = {
|
|
73
95
|
0: {
|
|
74
|
-
0: { v:
|
|
75
|
-
1: {
|
|
96
|
+
0: { v: '金额', t: 1 },
|
|
97
|
+
1: { v: 12, t: 2 },
|
|
98
|
+
2: { f: '=B1*2', v: 24, t: 2 },
|
|
76
99
|
},
|
|
77
100
|
}
|
|
101
|
+
|
|
78
102
|
const snapshot = validateWorkbook(doc)
|
|
103
|
+
const searchableText = workbookText(snapshot)
|
|
79
104
|
```
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
工作簿结构为 `{ type: 'workbook', formatVersion: 1, workbook: ... }`:
|
|
82
107
|
|
|
83
|
-
|
|
108
|
+
- `f` 保存公式表达式,`v` 保存值或公式计算缓存。
|
|
109
|
+
- `validateWorkbook` 返回独立快照,检查越界、危险属性、非法值和重叠合并。
|
|
110
|
+
- 核心包保存和校验公式,不执行公式计算。可视编辑和 XLSX 转换使用 `wendang-vue`。
|
|
111
|
+
- 工作簿采用与 Univer 1.1.0 兼容的数据结构;升级引擎大版本时需检查格式兼容。
|
|
84
112
|
|
|
85
|
-
|
|
113
|
+
| 限制 | 上限 |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| Sheet 数 | 20 |
|
|
116
|
+
| 每表行数 / 列数 | 10000 / 200 |
|
|
117
|
+
| 实际单元格总数 | 50000 |
|
|
118
|
+
| JSON 大小 | 4 MiB |
|
|
86
119
|
|
|
87
|
-
|
|
120
|
+
## 思维导图
|
|
88
121
|
|
|
89
|
-
|
|
122
|
+
```ts
|
|
123
|
+
import {
|
|
124
|
+
createMindMap,
|
|
125
|
+
readMindMap,
|
|
126
|
+
mindMapToJson,
|
|
127
|
+
} from 'wendang/mindmap'
|
|
128
|
+
|
|
129
|
+
const json = createMindMap('both')
|
|
130
|
+
const model = readMindMap(json)
|
|
131
|
+
|
|
132
|
+
if (model) {
|
|
133
|
+
model.topics[0].text = '项目计划'
|
|
134
|
+
const snapshot = mindMapToJson(model)
|
|
135
|
+
console.log(snapshot)
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
| API | 用途 |
|
|
140
|
+
| --- | --- |
|
|
141
|
+
| `createMindMap(layout?)` | 创建可持久化的 `MindMapJson` |
|
|
142
|
+
| `readMindMap(json)` | 解析为 `MindMapModel`,无效内容返回 `null` |
|
|
143
|
+
| `mindMapToJson(model)` | 将模型序列化为 JSON |
|
|
144
|
+
|
|
145
|
+
导图当前 `formatVersion` 为 `3`,支持受支持旧版的读取。主题和关系线拥有稳定 ID,支持主题文字、富文本、描述、备注、附件及样式;单图最多 500 个主题,单主题标题最多 2000 字符。
|
|
146
|
+
|
|
147
|
+
持久化 JSON 数据;视口和选区属于展示状态。复制分支应重新生成身份,避免讨论锚点指向旧主题。
|
|
148
|
+
|
|
149
|
+
## 导入入口
|
|
150
|
+
|
|
151
|
+
| 入口 | 内容 |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `wendang` | 校验、版本、主要类型、工作簿和导图创建函数 |
|
|
154
|
+
| `wendang/schema` | 校验服务、异常类型、内容版本和节点白名单 |
|
|
155
|
+
| `wendang/document` | 文档类型、节点目录、文本工具和校验 |
|
|
156
|
+
| `wendang/spreadsheet` | 工作簿类型、创建、校验和文本提取 |
|
|
157
|
+
| `wendang/mindmap` | 导图模型、解析、序列化、布局、分支和搜索 |
|
|
158
|
+
| `wendang/types` | 文档、工作簿、导图及讨论类型 |
|
|
90
159
|
|
|
91
|
-
|
|
160
|
+
应用应通过以上入口导入,不引用 `dist` 内部文件。
|
|
92
161
|
|
|
93
|
-
|
|
94
|
-
2. 关闭新增按钮不能剥离已有内容;不支持的更高版本提示升级或只读保留。
|
|
95
|
-
3. 不把 HTML、截图或绘图坐标当作唯一源数据。
|
|
96
|
-
4. 核心不自动迁移宿主数据库;迁移必须有明确操作、样本和回退,失败保留原文。
|
|
97
|
-
5. 自定义节点必须同步编辑、阅读、校验和导出,不仅放宽前端 JSON。
|
|
98
|
-
6. ESM / CommonJS 通过实际 tarball 消费验证,禁止靠源码路径掩盖缺失导出。
|
|
162
|
+
## 数据与升级规范
|
|
99
163
|
|
|
100
|
-
|
|
164
|
+
- npm 包版本、文档 `schemaVersion` 与工作簿 / 导图 `formatVersion` 分别管理。
|
|
165
|
+
- 保存时同时保存内容和对应格式版本;加载更高版本失败时保留原始数据。
|
|
166
|
+
- HTML、截图及渲染坐标不能替代 JSON 源数据。
|
|
167
|
+
- 自定义节点需同时支持编辑、阅读、校验和导出;只增加前端节点不会自动放宽后端校验。
|
|
168
|
+
- 数据库升级和历史数据迁移由应用控制。
|
|
101
169
|
|
|
102
|
-
|
|
170
|
+
## License
|
|
103
171
|
|
|
104
|
-
|
|
172
|
+
采用随包附带的 [Wendang 商业使用许可](LICENSE):允许免费商业使用、应用集成修改和随应用分发运行代码,无需公开应用源码。独立 SDK 或源码产品的再发布、再许可及出售需书面授权。
|
package/dist/cjs/document.js
CHANGED
|
@@ -1,19 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./schema.js"), exports);
|
|
18
|
-
__exportStar(require("./shared/node-catalog.js"), exports);
|
|
19
|
-
__exportStar(require("./shared/doc-text.js"), exports);
|
|
1
|
+
"use strict";var e=this&&this.__createBinding||(Object.create?function(e,r,t,o){void 0===o&&(o=t);var i=Object.getOwnPropertyDescriptor(r,t);i&&!("get"in i?!r.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(e,o,i)}:function(e,r,t,o){void 0===o&&(o=t),e[o]=r[t]}),r=this&&this.__exportStar||function(r,t){for(var o in r)"default"===o||Object.prototype.hasOwnProperty.call(t,o)||e(t,r,o)};Object.defineProperty(exports,"__esModule",{value:!0}),r(require("./schema.js"),exports),r(require("./shared/node-catalog.js"),exports),r(require("./shared/doc-text.js"),exports),r(require("./shared/headings.js"),exports);
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,25 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.mindMapToJson = exports.readMindMap = exports.createMindMap = exports.validateWorkbook = exports.emptyWorkbook = void 0;
|
|
18
|
-
__exportStar(require("./schema.js"), exports);
|
|
19
|
-
var spreadsheet_js_1 = require("./spreadsheet.js");
|
|
20
|
-
Object.defineProperty(exports, "emptyWorkbook", { enumerable: true, get: function () { return spreadsheet_js_1.emptyWorkbook; } });
|
|
21
|
-
Object.defineProperty(exports, "validateWorkbook", { enumerable: true, get: function () { return spreadsheet_js_1.validateWorkbook; } });
|
|
22
|
-
var mindmap_js_1 = require("./mindmap.js");
|
|
23
|
-
Object.defineProperty(exports, "createMindMap", { enumerable: true, get: function () { return mindmap_js_1.createMindMap; } });
|
|
24
|
-
Object.defineProperty(exports, "readMindMap", { enumerable: true, get: function () { return mindmap_js_1.readMindMap; } });
|
|
25
|
-
Object.defineProperty(exports, "mindMapToJson", { enumerable: true, get: function () { return mindmap_js_1.mindMapToJson; } });
|
|
1
|
+
"use strict";var e=this&&this.__createBinding||(Object.create?function(e,r,t,o){void 0===o&&(o=t);var n=Object.getOwnPropertyDescriptor(r,t);n&&!("get"in n?!r.__esModule:n.writable||n.configurable)||(n={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(e,o,n)}:function(e,r,t,o){void 0===o&&(o=t),e[o]=r[t]}),r=this&&this.__exportStar||function(r,t){for(var o in r)"default"===o||Object.prototype.hasOwnProperty.call(t,o)||e(t,r,o)};Object.defineProperty(exports,"__esModule",{value:!0}),exports.mindMapToJson=exports.readMindMap=exports.createMindMap=exports.validateWorkbook=exports.emptyWorkbook=void 0,r(require("./schema.js"),exports);var t=require("./spreadsheet.js");Object.defineProperty(exports,"emptyWorkbook",{enumerable:!0,get:function(){return t.emptyWorkbook}}),Object.defineProperty(exports,"validateWorkbook",{enumerable:!0,get:function(){return t.validateWorkbook}});var o=require("./mindmap.js");Object.defineProperty(exports,"createMindMap",{enumerable:!0,get:function(){return o.createMindMap}}),Object.defineProperty(exports,"readMindMap",{enumerable:!0,get:function(){return o.readMindMap}}),Object.defineProperty(exports,"mindMapToJson",{enumerable:!0,get:function(){return o.mindMapToJson}});
|
package/dist/cjs/mindmap.js
CHANGED
|
@@ -1,22 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.validateMindMap = void 0;
|
|
18
|
-
__exportStar(require("./shared/mind-map.js"), exports);
|
|
19
|
-
__exportStar(require("./shared/mind-map-phase2.js"), exports);
|
|
20
|
-
__exportStar(require("./shared/mind-map-folding.js"), exports);
|
|
21
|
-
var mind_map_js_1 = require("./validation/mind-map.js");
|
|
22
|
-
Object.defineProperty(exports, "validateMindMap", { enumerable: true, get: function () { return mind_map_js_1.validateMindMap; } });
|
|
1
|
+
"use strict";var e=this&&this.__createBinding||(Object.create?function(e,r,t,i){void 0===i&&(i=t);var a=Object.getOwnPropertyDescriptor(r,t);a&&!("get"in a?!r.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return r[t]}}),Object.defineProperty(e,i,a)}:function(e,r,t,i){void 0===i&&(i=t),e[i]=r[t]}),r=this&&this.__exportStar||function(r,t){for(var i in r)"default"===i||Object.prototype.hasOwnProperty.call(t,i)||e(t,r,i)};Object.defineProperty(exports,"__esModule",{value:!0}),exports.validateMindMap=void 0,r(require("./shared/mind-map.js"),exports),r(require("./shared/mind-map-phase2.js"),exports),r(require("./shared/mind-map-folding.js"),exports);var t=require("./validation/mind-map.js");Object.defineProperty(exports,"validateMindMap",{enumerable:!0,get:function(){return t.validateMindMap}});
|
package/dist/cjs/schema.js
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ALLOWED_MARKS = exports.ALLOWED_NODES = exports.ContentValidationError = exports.SCHEMA_VERSION = exports.ContentSchemaService = void 0;
|
|
4
|
-
var schema_js_1 = require("./validation/schema.js");
|
|
5
|
-
Object.defineProperty(exports, "ContentSchemaService", { enumerable: true, get: function () { return schema_js_1.ContentSchemaService; } });
|
|
6
|
-
Object.defineProperty(exports, "SCHEMA_VERSION", { enumerable: true, get: function () { return schema_js_1.SCHEMA_VERSION; } });
|
|
7
|
-
var error_js_1 = require("./validation/error.js");
|
|
8
|
-
Object.defineProperty(exports, "ContentValidationError", { enumerable: true, get: function () { return error_js_1.ContentValidationError; } });
|
|
9
|
-
var doc_node_whitelist_js_1 = require("./validation/doc-node-whitelist.js");
|
|
10
|
-
Object.defineProperty(exports, "ALLOWED_NODES", { enumerable: true, get: function () { return doc_node_whitelist_js_1.ALLOWED_NODES; } });
|
|
11
|
-
Object.defineProperty(exports, "ALLOWED_MARKS", { enumerable: true, get: function () { return doc_node_whitelist_js_1.ALLOWED_MARKS; } });
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ALLOWED_MARKS=exports.ALLOWED_NODES=exports.ContentValidationError=exports.SCHEMA_VERSION=exports.ContentSchemaService=void 0;var e=require("./validation/schema.js");Object.defineProperty(exports,"ContentSchemaService",{enumerable:!0,get:function(){return e.ContentSchemaService}}),Object.defineProperty(exports,"SCHEMA_VERSION",{enumerable:!0,get:function(){return e.SCHEMA_VERSION}});var r=require("./validation/error.js");Object.defineProperty(exports,"ContentValidationError",{enumerable:!0,get:function(){return r.ContentValidationError}});var t=require("./validation/doc-node-whitelist.js");Object.defineProperty(exports,"ALLOWED_NODES",{enumerable:!0,get:function(){return t.ALLOWED_NODES}}),Object.defineProperty(exports,"ALLOWED_MARKS",{enumerable:!0,get:function(){return t.ALLOWED_MARKS}});
|
|
@@ -1,201 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* 行内评论的锚点定位(纯函数,可单测)。
|
|
4
|
-
*
|
|
5
|
-
* ## 为什么不能存位置
|
|
6
|
-
*
|
|
7
|
-
* 直觉做法是「记录选中文字的 start/end 偏移」。但文档会被编辑:
|
|
8
|
-
* 在选区前面插入一个字,所有后续位置全部偏移——锚点立刻指向错误文字,
|
|
9
|
-
* 而且**错得很安静**(评论跑到别的地方,没人会立刻发现)。
|
|
10
|
-
*
|
|
11
|
-
* ## 采用方案:文本引用(TextQuoteSelector 思路,W3C Web Annotation)
|
|
12
|
-
*
|
|
13
|
-
* 存三样东西:
|
|
14
|
-
* - `quote`:选中的原文
|
|
15
|
-
* - `prefix` / `suffix`:前后各一小段上下文(用于区分重复文本)
|
|
16
|
-
*
|
|
17
|
-
* 定位时在文档纯文本里搜索 quote;有多处命中时,用 prefix/suffix 的匹配长度打分,
|
|
18
|
-
* 取最匹配的一处。这样:
|
|
19
|
-
* - 在文档**别处**编辑(不碰该段文字)→ 锚点依然准确定位;
|
|
20
|
-
* - 该段文字本身被改动 → 匹配不到,此时用 prefix+suffix 的接缝尽力定位,
|
|
21
|
-
* 返回一个「降级」结果(exact=false),前端据此提示「原文已改动」;
|
|
22
|
-
* - 完全找不到(整段被删)→ 返回 null,前端把评论归入「已失联」,
|
|
23
|
-
* **而不是指向一处无关文字**。
|
|
24
|
-
*
|
|
25
|
-
* 宁可显示「已失联」,也不要指向错误位置——后者会让用户读到与上下文无关的评论,
|
|
26
|
-
* 比看得见的缺失更有害。
|
|
27
|
-
*/
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.ANCHOR_QUOTE_MAX = exports.ANCHOR_CONTEXT_LENGTH = void 0;
|
|
30
|
-
exports.flattenDocText = flattenDocText;
|
|
31
|
-
exports.locateBlock = locateBlock;
|
|
32
|
-
exports.resolveAnchor = resolveAnchor;
|
|
33
|
-
exports.commonSuffixLength = commonSuffixLength;
|
|
34
|
-
exports.commonPrefixLength = commonPrefixLength;
|
|
35
|
-
exports.clipContext = clipContext;
|
|
36
|
-
/** 上下文最大长度(与提交时截断长度一致)。 */
|
|
37
|
-
exports.ANCHOR_CONTEXT_LENGTH = 64;
|
|
38
|
-
exports.ANCHOR_QUOTE_MAX = 500;
|
|
39
|
-
/**
|
|
40
|
-
* 把若干块文本拼成扁平文本,记录片段边界。
|
|
41
|
-
* 块之间插入换行(可用块间匹配不应跨越块边界,换行同时避免把块首块尾误连成词)。
|
|
42
|
-
*/
|
|
43
|
-
function flattenDocText(blocks) {
|
|
44
|
-
const segments = [];
|
|
45
|
-
let text = '';
|
|
46
|
-
blocks.forEach((blockText, blockIndex) => {
|
|
47
|
-
if (blockIndex > 0)
|
|
48
|
-
text += '\n';
|
|
49
|
-
segments.push({ start: text.length, blockIndex, length: blockText.length });
|
|
50
|
-
text += blockText;
|
|
51
|
-
});
|
|
52
|
-
return { text, segments };
|
|
53
|
-
}
|
|
54
|
-
/** 由扁平字符偏移定位到 (块索引, 块内偏移)。 */
|
|
55
|
-
function locateBlock(flat, charOffset) {
|
|
56
|
-
for (const seg of flat.segments) {
|
|
57
|
-
if (charOffset >= seg.start && charOffset <= seg.start + seg.length) {
|
|
58
|
-
return { blockIndex: seg.blockIndex, offsetInBlock: charOffset - seg.start };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// 落在块间换行或末尾时,归到最后一个片段
|
|
62
|
-
const last = flat.segments[flat.segments.length - 1];
|
|
63
|
-
if (!last)
|
|
64
|
-
return null;
|
|
65
|
-
if (charOffset > last.start + last.length) {
|
|
66
|
-
return { blockIndex: last.blockIndex, offsetInBlock: last.length };
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* 定位锚点。返回 null 表示无法可信定位(整段被删),调用方应标记为「已失联」。
|
|
72
|
-
*/
|
|
73
|
-
function resolveAnchor(text, anchor) {
|
|
74
|
-
const quote = (anchor.quote ?? '').trim();
|
|
75
|
-
if (quote.length === 0)
|
|
76
|
-
return null;
|
|
77
|
-
const prefix = anchor.prefix ?? '';
|
|
78
|
-
const suffix = anchor.suffix ?? '';
|
|
79
|
-
const expectedStart = anchor.start ?? -1;
|
|
80
|
-
// 1) 收集 quote 的全部出现位置
|
|
81
|
-
const candidates = [];
|
|
82
|
-
let idx = text.indexOf(quote);
|
|
83
|
-
while (idx !== -1) {
|
|
84
|
-
candidates.push(idx);
|
|
85
|
-
// 从下一个字符继续,避免重叠匹配导致死循环
|
|
86
|
-
idx = text.indexOf(quote, idx + 1);
|
|
87
|
-
}
|
|
88
|
-
if (candidates.length > 0) {
|
|
89
|
-
let best = null;
|
|
90
|
-
for (const start of candidates) {
|
|
91
|
-
const score = scoreCandidate(text, start, quote.length, prefix, suffix, expectedStart);
|
|
92
|
-
if (!best || score > best.score)
|
|
93
|
-
best = { start, score };
|
|
94
|
-
}
|
|
95
|
-
if (best) {
|
|
96
|
-
return {
|
|
97
|
-
from: best.start,
|
|
98
|
-
to: best.start + quote.length,
|
|
99
|
-
score: best.score,
|
|
100
|
-
exact: true,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// 2) quote 已不在文档中:用上下文降级定位,返回零长度锚点。
|
|
105
|
-
// 两种情况:
|
|
106
|
-
// a) quote 整段被删除 → prefix 与 suffix 在文档中相邻,用接缝精确落点;
|
|
107
|
-
// b) quote 被改写但上下文还在 → 用较长的一侧贴住,落在其边缘。
|
|
108
|
-
// 两者都标记 exact=false,前端据此提示「原文已改动」。
|
|
109
|
-
// 2a) prefix 与 suffix 相邻(说明中间的原引用被删掉了)
|
|
110
|
-
if (prefix.length > 0 && suffix.length > 0) {
|
|
111
|
-
const needle = prefix + suffix;
|
|
112
|
-
const at = text.indexOf(needle);
|
|
113
|
-
if (at !== -1) {
|
|
114
|
-
const pos = at + prefix.length;
|
|
115
|
-
return { from: pos, to: pos, score: 50, exact: false };
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// 2b) 用较长的一侧贴住边缘。
|
|
119
|
-
// 注意两点(都是实测教训):
|
|
120
|
-
// - 阈值取 4 而非 8:中文一个词常只有 2–4 字,阈值过高会让中文文档
|
|
121
|
-
// 几乎无法降级定位;
|
|
122
|
-
// - 必须遍历**全部**出现位置并取最接近原偏移的那个:
|
|
123
|
-
// 短上下文在文档中可能重复,取首个出现会落到错误位置。
|
|
124
|
-
const side = prefix.length >= suffix.length ? prefix : suffix;
|
|
125
|
-
if (side.length >= 4) {
|
|
126
|
-
const at = nearestOccurrence(text, side, expectedStart);
|
|
127
|
-
if (at !== -1) {
|
|
128
|
-
const pos = prefix.length >= suffix.length ? at + side.length : at;
|
|
129
|
-
return { from: pos, to: pos, score: 10, exact: false };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* 在文本中找出 needle 的全部出现位置,返回最接近 expected 的那个。
|
|
136
|
-
* expected < 0(无提示)时退化为返回第一个出现位置。
|
|
137
|
-
* 这样短上下文重复时不会盲目落到首次出现处。
|
|
138
|
-
*/
|
|
139
|
-
function nearestOccurrence(text, needle, expected) {
|
|
140
|
-
if (needle.length === 0)
|
|
141
|
-
return -1;
|
|
142
|
-
const positions = [];
|
|
143
|
-
let idx = text.indexOf(needle);
|
|
144
|
-
while (idx !== -1) {
|
|
145
|
-
positions.push(idx);
|
|
146
|
-
if (positions.length > 500)
|
|
147
|
-
break; // 防御:极端重复文本
|
|
148
|
-
idx = text.indexOf(needle, idx + 1);
|
|
149
|
-
}
|
|
150
|
-
if (positions.length === 0)
|
|
151
|
-
return -1;
|
|
152
|
-
if (expected < 0)
|
|
153
|
-
return positions[0];
|
|
154
|
-
let best = positions[0];
|
|
155
|
-
for (const p of positions) {
|
|
156
|
-
if (Math.abs(p - expected) < Math.abs(best - expected))
|
|
157
|
-
best = p;
|
|
158
|
-
}
|
|
159
|
-
return best;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* 给候选位置打分:
|
|
163
|
-
* - 引用本身匹配是基础分;
|
|
164
|
-
* - 前后文匹配越长越可信(能区分「同一句话在文档里出现多次」);
|
|
165
|
-
* - 与提交时偏移越近,略微加分(仅在文本重复且上下文缺失时起作用)。
|
|
166
|
-
*/
|
|
167
|
-
function scoreCandidate(text, start, quoteLength, prefix, suffix, expectedStart) {
|
|
168
|
-
let score = 1000;
|
|
169
|
-
if (prefix.length > 0) {
|
|
170
|
-
const actualPrefix = text.slice(Math.max(0, start - prefix.length), start);
|
|
171
|
-
score += commonSuffixLength(actualPrefix, prefix) * 4;
|
|
172
|
-
}
|
|
173
|
-
if (suffix.length > 0) {
|
|
174
|
-
const actualSuffix = text.slice(start + quoteLength, start + quoteLength + suffix.length);
|
|
175
|
-
score += commonPrefixLength(actualSuffix, suffix) * 4;
|
|
176
|
-
}
|
|
177
|
-
if (expectedStart >= 0) {
|
|
178
|
-
score -= Math.min(Math.abs(start - expectedStart), 200);
|
|
179
|
-
}
|
|
180
|
-
return score;
|
|
181
|
-
}
|
|
182
|
-
/** 两个字符串从末尾开始相同的字符数。 */
|
|
183
|
-
function commonSuffixLength(a, b) {
|
|
184
|
-
let n = 0;
|
|
185
|
-
while (n < a.length && n < b.length && a[a.length - 1 - n] === b[b.length - 1 - n]) {
|
|
186
|
-
n += 1;
|
|
187
|
-
}
|
|
188
|
-
return n;
|
|
189
|
-
}
|
|
190
|
-
/** 两个字符串从头开始相同的字符数。 */
|
|
191
|
-
function commonPrefixLength(a, b) {
|
|
192
|
-
let n = 0;
|
|
193
|
-
while (n < a.length && n < b.length && a[n] === b[n]) {
|
|
194
|
-
n += 1;
|
|
195
|
-
}
|
|
196
|
-
return n;
|
|
197
|
-
}
|
|
198
|
-
/** 截断上下文到限定长度(提交时使用)。 */
|
|
199
|
-
function clipContext(text) {
|
|
200
|
-
return text.slice(0, exports.ANCHOR_CONTEXT_LENGTH);
|
|
201
|
-
}
|
|
1
|
+
"use strict";function scoreCandidate(t,e,n,o,r,l){let s=1e3;return o.length>0&&(s+=4*commonSuffixLength(t.slice(Math.max(0,e-o.length),e),o)),r.length>0&&(s+=4*commonPrefixLength(t.slice(e+n,e+n+r.length),r)),l>=0&&(s-=Math.min(Math.abs(e-l),200)),s}function commonSuffixLength(t,e){let n=0;for(;n<t.length&&n<e.length&&t[t.length-1-n]===e[e.length-1-n];)n+=1;return n}function commonPrefixLength(t,e){let n=0;for(;n<t.length&&n<e.length&&t[n]===e[n];)n+=1;return n}Object.defineProperty(exports,"__esModule",{value:!0}),exports.ANCHOR_QUOTE_MAX=exports.ANCHOR_CONTEXT_LENGTH=void 0,exports.flattenDocText=function flattenDocText(t){const e=[];let n="";return t.forEach((t,o)=>{o>0&&(n+="\n"),e.push({start:n.length,blockIndex:o,length:t.length}),n+=t}),{text:n,segments:e}},exports.locateBlock=function locateBlock(t,e){for(const n of t.segments)if(e>=n.start&&e<=n.start+n.length)return{blockIndex:n.blockIndex,offsetInBlock:e-n.start};const n=t.segments[t.segments.length-1];return n&&e>n.start+n.length?{blockIndex:n.blockIndex,offsetInBlock:n.length}:null},exports.resolveAnchor=function resolveAnchor(t,e){const n=(e.quote??"").trim();if(0===n.length)return null;const o=e.prefix??"",r=e.suffix??"",l=e.start??-1,s=[];let c=t.indexOf(n);for(;-1!==c;)s.push(c),c=t.indexOf(n,c+1);if(s.length>0){let e=null;for(const c of s){const s=scoreCandidate(t,c,n.length,o,r,l);(!e||s>e.score)&&(e={start:c,score:s})}if(e)return{from:e.start,to:e.start+n.length,score:e.score,exact:!0}}if(o.length>0&&r.length>0){const e=o+r,n=t.indexOf(e);if(-1!==n){const t=n+o.length;return{from:t,to:t,score:50,exact:!1}}}const f=o.length>=r.length?o:r;if(f.length>=4){const e=function nearestOccurrence(t,e,n){if(0===e.length)return-1;const o=[];let r=t.indexOf(e);for(;-1!==r&&(o.push(r),!(o.length>500));)r=t.indexOf(e,r+1);if(0===o.length)return-1;if(n<0)return o[0];let l=o[0];for(const t of o)Math.abs(t-n)<Math.abs(l-n)&&(l=t);return l}(t,f,l);if(-1!==e){const t=o.length>=r.length?e+f.length:e;return{from:t,to:t,score:10,exact:!1}}}return null},exports.commonSuffixLength=commonSuffixLength,exports.commonPrefixLength=commonPrefixLength,exports.clipContext=function clipContext(t){return t.slice(0,exports.ANCHOR_CONTEXT_LENGTH)},exports.ANCHOR_CONTEXT_LENGTH=64,exports.ANCHOR_QUOTE_MAX=500;
|