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.
Files changed (98) hide show
  1. package/LICENSE +43 -2
  2. package/NOTICE.md +1 -1
  3. package/README.md +120 -52
  4. package/dist/cjs/document.js +1 -19
  5. package/dist/cjs/index.js +1 -25
  6. package/dist/cjs/mindmap.js +1 -22
  7. package/dist/cjs/schema.js +1 -11
  8. package/dist/cjs/shared/anchor.js +1 -201
  9. package/dist/cjs/shared/callout.js +1 -64
  10. package/dist/cjs/shared/code-block.js +1 -33
  11. package/dist/cjs/shared/code-languages.js +1 -51
  12. package/dist/cjs/shared/doc-compatibility.js +1 -23
  13. package/dist/cjs/shared/doc-text.js +1 -52
  14. package/dist/cjs/shared/document-colors.js +1 -61
  15. package/dist/cjs/shared/headings.js +1 -0
  16. package/dist/cjs/shared/inline-comments.js +1 -179
  17. package/dist/cjs/shared/mind-map-folding.js +1 -14
  18. package/dist/cjs/shared/mind-map-phase2.js +1 -133
  19. package/dist/cjs/shared/mind-map.js +1 -445
  20. package/dist/cjs/shared/mind-topic-text.js +1 -57
  21. package/dist/cjs/shared/node-catalog.js +1 -62
  22. package/dist/cjs/shared/presence.js +1 -141
  23. package/dist/cjs/shared/safe-href.js +1 -36
  24. package/dist/cjs/shared/table-cell-format.js +1 -18
  25. package/dist/cjs/shared/table-layout.js +1 -28
  26. package/dist/cjs/shared/types.js +1 -2
  27. package/dist/cjs/shared/video-embed.js +1 -102
  28. package/dist/cjs/shared/workbook.js +1 -152
  29. package/dist/cjs/spreadsheet.js +1 -17
  30. package/dist/cjs/types.js +1 -17
  31. package/dist/cjs/validation/callout.js +1 -17
  32. package/dist/cjs/validation/doc-node-whitelist.js +1 -71
  33. package/dist/cjs/validation/error.js +1 -17
  34. package/dist/cjs/validation/mind-map.js +1 -129
  35. package/dist/cjs/validation/schema-version.js +1 -5
  36. package/dist/cjs/validation/schema.js +1 -376
  37. package/dist/cjs/validation/video-embed.js +1 -17
  38. package/dist/cjs/validation/workbook.js +1 -17
  39. package/dist/esm/document.js +1 -3
  40. package/dist/esm/index.js +1 -3
  41. package/dist/esm/mindmap.js +1 -4
  42. package/dist/esm/schema.js +1 -3
  43. package/dist/esm/shared/anchor.js +1 -192
  44. package/dist/esm/shared/callout.js +1 -56
  45. package/dist/esm/shared/code-block.js +1 -25
  46. package/dist/esm/shared/code-languages.js +1 -46
  47. package/dist/esm/shared/doc-compatibility.js +1 -20
  48. package/dist/esm/shared/doc-text.js +1 -48
  49. package/dist/esm/shared/document-colors.js +1 -56
  50. package/dist/esm/shared/headings.js +1 -0
  51. package/dist/esm/shared/inline-comments.js +1 -173
  52. package/dist/esm/shared/mind-map-folding.js +1 -10
  53. package/dist/esm/shared/mind-map-phase2.js +1 -121
  54. package/dist/esm/shared/mind-map.js +1 -427
  55. package/dist/esm/shared/mind-topic-text.js +1 -49
  56. package/dist/esm/shared/node-catalog.js +1 -57
  57. package/dist/esm/shared/presence.js +1 -130
  58. package/dist/esm/shared/safe-href.js +1 -32
  59. package/dist/esm/shared/table-cell-format.js +1 -14
  60. package/dist/esm/shared/table-layout.js +1 -23
  61. package/dist/esm/shared/types.js +1 -1
  62. package/dist/esm/shared/video-embed.js +1 -96
  63. package/dist/esm/shared/workbook.js +1 -144
  64. package/dist/esm/spreadsheet.js +1 -1
  65. package/dist/esm/types.js +1 -1
  66. package/dist/esm/validation/callout.js +1 -1
  67. package/dist/esm/validation/doc-node-whitelist.js +1 -68
  68. package/dist/esm/validation/error.js +1 -13
  69. package/dist/esm/validation/mind-map.js +1 -125
  70. package/dist/esm/validation/schema-version.js +1 -2
  71. package/dist/esm/validation/schema.js +1 -372
  72. package/dist/esm/validation/video-embed.js +1 -1
  73. package/dist/esm/validation/workbook.js +1 -1
  74. package/dist/types/document.d.ts +1 -0
  75. package/dist/types/shared/anchor.d.ts +0 -55
  76. package/dist/types/shared/callout.d.ts +39 -2
  77. package/dist/types/shared/code-block.d.ts +0 -1
  78. package/dist/types/shared/code-languages.d.ts +0 -19
  79. package/dist/types/shared/doc-text.d.ts +0 -14
  80. package/dist/types/shared/document-colors.d.ts +0 -4
  81. package/dist/types/shared/headings.d.ts +7 -0
  82. package/dist/types/shared/inline-comments.d.ts +0 -42
  83. package/dist/types/shared/mind-map-folding.d.ts +0 -2
  84. package/dist/types/shared/mind-map.d.ts +0 -4
  85. package/dist/types/shared/mind-topic-text.d.ts +0 -2
  86. package/dist/types/shared/node-catalog.d.ts +0 -17
  87. package/dist/types/shared/presence.d.ts +0 -51
  88. package/dist/types/shared/safe-href.d.ts +0 -1
  89. package/dist/types/shared/table-cell-format.d.ts +0 -1
  90. package/dist/types/shared/table-layout.d.ts +0 -3
  91. package/dist/types/shared/types.d.ts +0 -4
  92. package/dist/types/shared/video-embed.d.ts +9 -2
  93. package/dist/types/shared/workbook.d.ts +0 -2
  94. package/dist/types/validation/doc-node-whitelist.d.ts +0 -19
  95. package/dist/types/validation/mind-map.d.ts +0 -2
  96. package/dist/types/validation/schema-version.d.ts +0 -1
  97. package/dist/types/validation/schema.d.ts +0 -34
  98. package/package.json +9 -9
@@ -1,152 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WORKBOOK_LIMITS = void 0;
4
- exports.isWorkbookDocument = isWorkbookDocument;
5
- exports.emptyWorkbook = emptyWorkbook;
6
- exports.validateWorkbook = validateWorkbook;
7
- exports.workbookCellText = workbookCellText;
8
- exports.workbookText = workbookText;
9
- exports.WORKBOOK_LIMITS = { sheets: 20, rows: 10000, columns: 200, cells: 50000, bytes: 4 * 1024 * 1024 };
10
- function isWorkbookDocument(value) {
11
- return !!value && typeof value === 'object' && value.type === 'workbook';
12
- }
13
- function emptyWorkbook(id) {
14
- return {
15
- type: 'workbook', formatVersion: 1,
16
- workbook: {
17
- id, name: '工作簿', appVersion: '1.1.0', locale: 'zhCN',
18
- sheetOrder: ['sheet1'],
19
- sheets: { sheet1: { id: 'sheet1', name: 'Sheet1', rowCount: 1000, columnCount: 26, cellData: {} } },
20
- },
21
- };
22
- }
23
- function record(value) {
24
- return !!value && typeof value === 'object' && !Array.isArray(value);
25
- }
26
- function index(key, upper) {
27
- return /^(0|[1-9]\d*)$/.test(key) && Number(key) < upper;
28
- }
29
- /** Validate the complete snapshot without silently dropping supported engine attributes. */
30
- function validateWorkbook(raw) {
31
- const fail = (message) => { throw new Error(`工作表格式无效:${message}`); };
32
- if (!isWorkbookDocument(raw) || raw.formatVersion !== 1 || !record(raw.workbook))
33
- fail('不支持的版本');
34
- const doc = raw;
35
- const json = JSON.stringify(doc);
36
- if (new TextEncoder().encode(json).byteLength > exports.WORKBOOK_LIMITS.bytes)
37
- fail('超过 4MB');
38
- let nodes = 0;
39
- const walk = (value, depth) => {
40
- if (++nodes > 500000 || depth > 40)
41
- fail('结构过大或嵌套过深');
42
- if (typeof value === 'number' && !Number.isFinite(value))
43
- fail('包含非法数值');
44
- if (Array.isArray(value))
45
- value.forEach(item => walk(item, depth + 1));
46
- else if (record(value)) {
47
- if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
48
- fail('包含非法对象');
49
- for (const [key, item] of Object.entries(value)) {
50
- if (['__proto__', 'constructor', 'prototype'].includes(key))
51
- fail('包含非法属性');
52
- walk(item, depth + 1);
53
- }
54
- }
55
- };
56
- walk(doc, 0);
57
- const book = doc.workbook;
58
- if (typeof book.id !== 'string' || !book.id || book.id.length > 128 ||
59
- typeof book.name !== 'string' || book.name.length > 256)
60
- fail('工作簿名称或标识无效');
61
- if (!Array.isArray(book.sheetOrder) || !book.sheetOrder.length || book.sheetOrder.length > exports.WORKBOOK_LIMITS.sheets ||
62
- new Set(book.sheetOrder).size !== book.sheetOrder.length || !record(book.sheets) ||
63
- Object.keys(book.sheets).length !== book.sheetOrder.length)
64
- fail('表页数量或顺序无效');
65
- let cells = 0;
66
- const names = new Set();
67
- for (const id of book.sheetOrder) {
68
- if (typeof id !== 'string' || !id || id.length > 128)
69
- fail('表页标识无效');
70
- const sheet = book.sheets[id];
71
- if (!record(sheet) || sheet.id !== id || typeof sheet.name !== 'string' || !sheet.name.trim() ||
72
- sheet.name.length > 31 || /[\\/*?:[\]]/.test(sheet.name) || names.has(sheet.name.toLowerCase()))
73
- fail('表页名称无效或重复(最多 31 字符)');
74
- names.add(sheet.name.toLowerCase());
75
- if (!Number.isInteger(sheet.rowCount) || sheet.rowCount < 1 || sheet.rowCount > exports.WORKBOOK_LIMITS.rows ||
76
- !Number.isInteger(sheet.columnCount) || sheet.columnCount < 1 || sheet.columnCount > exports.WORKBOOK_LIMITS.columns)
77
- fail('行列超出上限');
78
- if (sheet.cellData !== undefined) {
79
- if (!record(sheet.cellData))
80
- fail('单元格结构无效');
81
- for (const [r, row] of Object.entries(sheet.cellData)) {
82
- if (!index(r, sheet.rowCount) || !record(row))
83
- fail('单元格行号无效');
84
- for (const [c, cell] of Object.entries(row)) {
85
- if (++cells > exports.WORKBOOK_LIMITS.cells)
86
- fail('单元格超过 50000 个');
87
- if (!index(c, sheet.columnCount))
88
- fail('单元格列号无效');
89
- if (cell === null)
90
- continue;
91
- if (!record(cell))
92
- fail('单元格结构无效');
93
- if (cell.v !== undefined && cell.v !== null && !['string', 'number', 'boolean'].includes(typeof cell.v))
94
- fail('单元格值无效');
95
- if (typeof cell.v === 'string' && cell.v.length > 16000)
96
- fail('单元格文字过长');
97
- if (cell.f !== undefined && (typeof cell.f !== 'string' || cell.f.length > 4000))
98
- fail('公式无效');
99
- if (cell.t !== undefined && (!Number.isInteger(cell.t) || Number(cell.t) < 0 || Number(cell.t) > 4))
100
- fail('单元格类型无效');
101
- if (cell.s !== undefined && cell.s !== null && typeof cell.s !== 'string' && !record(cell.s))
102
- fail('单元格样式无效');
103
- if (cell.p !== undefined && (!record(cell.p) || (cell.p.body !== undefined &&
104
- (!record(cell.p.body) || typeof cell.p.body.dataStream !== 'string' || cell.p.body.dataStream.length > 16000))))
105
- fail('单元格富文本无效');
106
- }
107
- }
108
- }
109
- for (const [data, upper] of [[sheet.rowData, sheet.rowCount], [sheet.columnData, sheet.columnCount]]) {
110
- if (data !== undefined && (!record(data) || Object.keys(data).some(key => !index(key, upper))))
111
- fail('行列属性越界');
112
- }
113
- if (sheet.mergeData !== undefined) {
114
- if (!Array.isArray(sheet.mergeData) || sheet.mergeData.length > exports.WORKBOOK_LIMITS.cells)
115
- fail('合并区域无效');
116
- const occupied = new Set();
117
- for (const range of sheet.mergeData) {
118
- if (!record(range) || ![range.startRow, range.endRow, range.startColumn, range.endColumn].every(Number.isInteger) ||
119
- range.startRow < 0 || range.endRow < range.startRow || range.endRow >= sheet.rowCount ||
120
- range.startColumn < 0 || range.endColumn < range.startColumn || range.endColumn >= sheet.columnCount)
121
- fail('合并区域越界');
122
- const area = (range.endRow - range.startRow + 1) * (range.endColumn - range.startColumn + 1);
123
- if (occupied.size + area > 200000)
124
- fail('合并区域总范围过大');
125
- for (let r = range.startRow; r <= range.endRow; r++) {
126
- for (let c = range.startColumn; c <= range.endColumn; c++) {
127
- const position = r * exports.WORKBOOK_LIMITS.columns + c;
128
- if (occupied.has(position))
129
- fail('合并区域重叠');
130
- occupied.add(position);
131
- }
132
- }
133
- }
134
- }
135
- }
136
- return JSON.parse(json);
137
- }
138
- function workbookCellText(cell) {
139
- if (!cell)
140
- return '';
141
- if (cell.p?.body?.dataStream)
142
- return cell.p.body.dataStream.replace(/[\r\n]+$/, '');
143
- if (cell.v !== undefined && cell.v !== null)
144
- return String(cell.v);
145
- return cell.f ?? '';
146
- }
147
- function workbookText(doc) {
148
- return doc.workbook.sheetOrder.map(id => {
149
- const sheet = doc.workbook.sheets[id];
150
- return `${sheet.name} ${Object.values(sheet.cellData ?? {}).flatMap(row => Object.values(row).map(workbookCellText)).join(' ')}`;
151
- }).join(' ').slice(0, 200000);
152
- }
1
+ "use strict";function isWorkbookDocument(e){return!!e&&"object"==typeof e&&"workbook"===e.type}function record(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function index(e,o){return/^(0|[1-9]\d*)$/.test(e)&&Number(e)<o}function workbookCellText(e){return e?e.p?.body?.dataStream?e.p.body.dataStream.replace(/[\r\n]+$/,""):void 0!==e.v&&null!==e.v?String(e.v):e.f??"":""}Object.defineProperty(exports,"__esModule",{value:!0}),exports.WORKBOOK_LIMITS=void 0,exports.isWorkbookDocument=isWorkbookDocument,exports.emptyWorkbook=function emptyWorkbook(e){return{type:"workbook",formatVersion:1,workbook:{id:e,name:"工作簿",appVersion:"1.1.0",locale:"zhCN",sheetOrder:["sheet1"],sheets:{sheet1:{id:"sheet1",name:"Sheet1",rowCount:1e3,columnCount:26,cellData:{}}}}}},exports.validateWorkbook=function validateWorkbook(e){const fail=e=>{throw new Error(`工作表格式无效:${e}`)};isWorkbookDocument(e)&&1===e.formatVersion&&record(e.workbook)||fail("不支持的版本");const o=e,t=JSON.stringify(o);(new TextEncoder).encode(t).byteLength>exports.WORKBOOK_LIMITS.bytes&&fail("超过 4MB");let r=0;const walk=(e,o)=>{if((++r>5e5||o>40)&&fail("结构过大或嵌套过深"),"number"!=typeof e||Number.isFinite(e)||fail("包含非法数值"),Array.isArray(e))e.forEach(e=>walk(e,o+1));else if(record(e)){Object.getPrototypeOf(e)!==Object.prototype&&null!==Object.getPrototypeOf(e)&&fail("包含非法对象");for(const[t,r]of Object.entries(e))["__proto__","constructor","prototype"].includes(t)&&fail("包含非法属性"),walk(r,o+1)}};walk(o,0);const n=o.workbook;("string"!=typeof n.id||!n.id||n.id.length>128||"string"!=typeof n.name||n.name.length>256)&&fail("工作簿名称或标识无效"),Array.isArray(n.sheetOrder)&&n.sheetOrder.length&&!(n.sheetOrder.length>exports.WORKBOOK_LIMITS.sheets)&&new Set(n.sheetOrder).size===n.sheetOrder.length&&record(n.sheets)&&Object.keys(n.sheets).length===n.sheetOrder.length||fail("表页数量或顺序无效");let s=0;const a=new Set;for(const e of n.sheetOrder){("string"!=typeof e||!e||e.length>128)&&fail("表页标识无效");const o=n.sheets[e];if((!record(o)||o.id!==e||"string"!=typeof o.name||!o.name.trim()||o.name.length>31||/[\\/*?:[\]]/.test(o.name)||a.has(o.name.toLowerCase()))&&fail("表页名称无效或重复(最多 31 字符)"),a.add(o.name.toLowerCase()),(!Number.isInteger(o.rowCount)||o.rowCount<1||o.rowCount>exports.WORKBOOK_LIMITS.rows||!Number.isInteger(o.columnCount)||o.columnCount<1||o.columnCount>exports.WORKBOOK_LIMITS.columns)&&fail("行列超出上限"),void 0!==o.cellData){record(o.cellData)||fail("单元格结构无效");for(const[e,t]of Object.entries(o.cellData)){index(e,o.rowCount)&&record(t)||fail("单元格行号无效");for(const[e,r]of Object.entries(t))++s>exports.WORKBOOK_LIMITS.cells&&fail("单元格超过 50000 个"),index(e,o.columnCount)||fail("单元格列号无效"),null!==r&&(record(r)||fail("单元格结构无效"),void 0===r.v||null===r.v||["string","number","boolean"].includes(typeof r.v)||fail("单元格值无效"),"string"==typeof r.v&&r.v.length>16e3&&fail("单元格文字过长"),void 0!==r.f&&("string"!=typeof r.f||r.f.length>4e3)&&fail("公式无效"),void 0!==r.t&&(!Number.isInteger(r.t)||Number(r.t)<0||Number(r.t)>4)&&fail("单元格类型无效"),void 0===r.s||null===r.s||"string"==typeof r.s||record(r.s)||fail("单元格样式无效"),void 0===r.p||record(r.p)&&(void 0===r.p.body||record(r.p.body)&&"string"==typeof r.p.body.dataStream&&!(r.p.body.dataStream.length>16e3))||fail("单元格富文本无效"))}}for(const[e,t]of[[o.rowData,o.rowCount],[o.columnData,o.columnCount]])void 0===e||record(e)&&!Object.keys(e).some(e=>!index(e,t))||fail("行列属性越界");if(void 0!==o.mergeData){(!Array.isArray(o.mergeData)||o.mergeData.length>exports.WORKBOOK_LIMITS.cells)&&fail("合并区域无效");const e=new Set;for(const t of o.mergeData){(!record(t)||![t.startRow,t.endRow,t.startColumn,t.endColumn].every(Number.isInteger)||t.startRow<0||t.endRow<t.startRow||t.endRow>=o.rowCount||t.startColumn<0||t.endColumn<t.startColumn||t.endColumn>=o.columnCount)&&fail("合并区域越界");const r=(t.endRow-t.startRow+1)*(t.endColumn-t.startColumn+1);e.size+r>2e5&&fail("合并区域总范围过大");for(let o=t.startRow;o<=t.endRow;o++)for(let r=t.startColumn;r<=t.endColumn;r++){const t=o*exports.WORKBOOK_LIMITS.columns+r;e.has(t)&&fail("合并区域重叠"),e.add(t)}}}}return JSON.parse(t)},exports.workbookCellText=workbookCellText,exports.workbookText=function workbookText(e){return e.workbook.sheetOrder.map(o=>{const t=e.workbook.sheets[o];return`${t.name} ${Object.values(t.cellData??{}).flatMap(e=>Object.values(e).map(workbookCellText)).join(" ")}`}).join(" ").slice(0,2e5)},exports.WORKBOOK_LIMITS={sheets:20,rows:1e4,columns:200,cells:5e4,bytes:4194304};
@@ -1,17 +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("./shared/workbook.js"), exports);
1
+ "use strict";var e=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var i=Object.getOwnPropertyDescriptor(t,r);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,i)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),t=this&&this.__exportStar||function(t,r){for(var o in t)"default"===o||Object.prototype.hasOwnProperty.call(r,o)||e(r,t,o)};Object.defineProperty(exports,"__esModule",{value:!0}),t(require("./shared/workbook.js"),exports);
package/dist/cjs/types.js CHANGED
@@ -1,17 +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("./shared/types.js"), exports);
1
+ "use strict";var e=this&&this.__createBinding||(Object.create?function(e,t,r,i){void 0===i&&(i=r);var o=Object.getOwnPropertyDescriptor(t,r);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,i,o)}:function(e,t,r,i){void 0===i&&(i=r),e[i]=t[r]}),t=this&&this.__exportStar||function(t,r){for(var i in t)"default"===i||Object.prototype.hasOwnProperty.call(r,i)||e(r,t,i)};Object.defineProperty(exports,"__esModule",{value:!0}),t(require("./shared/types.js"),exports);
@@ -1,17 +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("../shared/callout.js"), exports);
1
+ "use strict";var e=this&&this.__createBinding||(Object.create?function(e,t,r,i){void 0===i&&(i=r);var o=Object.getOwnPropertyDescriptor(t,r);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,i,o)}:function(e,t,r,i){void 0===i&&(i=r),e[i]=t[r]}),t=this&&this.__exportStar||function(t,r){for(var i in t)"default"===i||Object.prototype.hasOwnProperty.call(r,i)||e(r,t,i)};Object.defineProperty(exports,"__esModule",{value:!0}),t(require("../shared/callout.js"),exports);
@@ -1,71 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ALLOWED_MARKS = exports.ALLOWED_NODES = void 0;
4
- /**
5
- * 文档节点白名单(**纯数据,无依赖**)。
6
- *
7
- * 为什么单独成文件:白名单需要被三处引用——
8
- * 1) 服务端校验(doc-schema.service.ts)
9
- * 2) 一致性测试(与前端 node-catalog 交叉核对)
10
- * 3) 导出序列化器的防漂移测试
11
- * 若把它放在 doc-schema.service.ts 里,测试导入会连带加载 Nest 依赖,
12
- * 导致 spec 在测试环境下加载失败(实测:整个测试文件被静默跳过)。
13
- *
14
- * 因此这里只放数据,不放逻辑,任何一方都能安全引用。
15
- *
16
- * 新增节点时必须同时更新:
17
- * 1) 本文件
18
- * 2) 前端 web/src/shared/node-catalog.ts
19
- * 3) 导出序列化器 markdown-serializer.ts 的处理分支
20
- * 三处一致性由测试自动核对(读取真实文件,而非维护测试内副本)。
21
- */
22
- exports.ALLOWED_NODES = new Set([
23
- 'mindMapDescription', 'mindMapNote', 'mindMapRelation',
24
- 'mindMap',
25
- 'mindMapTopic',
26
- 'doc',
27
- 'paragraph',
28
- 'text',
29
- 'heading',
30
- 'bulletList',
31
- 'orderedList',
32
- 'listItem',
33
- // 待办列表:前端编辑器(TaskList/TaskItem)支持,导出序列化器也支持,
34
- // 但白名单此前漏了这两个节点 —— 导致「用户插入待办列表后保存必被拒」。
35
- // 由导入测试暴露(详见 doc-schema.service.spec.ts 的三方一致性断言)。
36
- 'taskList',
37
- 'taskItem',
38
- 'blockquote',
39
- 'codeBlock',
40
- 'horizontalRule',
41
- 'hardBreak',
42
- 'image',
43
- 'fileAttachment', // 视频或文件卡片(只存 attachmentId,不存存储地址)
44
- 'videoEmbed',
45
- 'callout', // 高亮块(容器,content: block+)
46
- // 分栏:columns(行,content: column+)包 column(栏,content: block+)。
47
- // 两个都要登记——只登记外层时,栏节点会在保存校验处被判为「不支持」而拒绝写入。
48
- 'columns',
49
- 'column',
50
- 'table',
51
- 'tableRow',
52
- 'tableHeader',
53
- 'tableCell',
54
- 'pageLink', // 内部页面引用 [[page]]
55
- 'mention', // @提及用户
56
- 'mathInline', // 行内公式(KaTeX)
57
- 'mathBlock', // 块级公式(KaTeX)
58
- ]);
59
- /** 允许的标记类型。 */
60
- exports.ALLOWED_MARKS = new Set([
61
- 'bold',
62
- 'italic',
63
- 'strike',
64
- 'code',
65
- 'link',
66
- // 行内样式:文字颜色与背景高亮。两者的颜色属性必须在
67
- // doc-schema.service.ts 的 ALLOWED_ATTRS 里同时登记,否则颜色值会被剥离、
68
- // 只剩一个空标记(实测的"颜色丢失但标记还在"就是这么来的)。
69
- 'textStyle',
70
- 'highlight',
71
- ]);
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ALLOWED_MARKS=exports.ALLOWED_NODES=void 0,exports.ALLOWED_NODES=new Set(["mindMapDescription","mindMapNote","mindMapRelation","mindMap","mindMapTopic","doc","paragraph","text","heading","bulletList","orderedList","listItem","taskList","taskItem","blockquote","codeBlock","horizontalRule","hardBreak","image","fileAttachment","videoEmbed","callout","columns","column","table","tableRow","tableHeader","tableCell","pageLink","mention","mathInline","mathBlock"]),exports.ALLOWED_MARKS=new Set(["bold","italic","strike","code","link","textStyle","highlight"]);
@@ -1,17 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ContentValidationError = void 0;
4
- class ContentValidationError extends Error {
5
- code;
6
- status;
7
- details;
8
- constructor(code, message, status = 422, details) {
9
- super(message);
10
- this.code = code;
11
- this.status = status;
12
- this.details = details;
13
- this.name = 'ContentValidationError';
14
- }
15
- static validation(message) { return new ContentValidationError('validation.failed', message); }
16
- }
17
- exports.ContentValidationError = ContentValidationError;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.ContentValidationError=void 0;class ContentValidationError extends Error{code;status;details;constructor(t,r,o=422,e){super(r),this.code=t,this.status=o,this.details=e,this.name="ContentValidationError"}static validation(t){return new ContentValidationError("validation.failed",t)}}exports.ContentValidationError=ContentValidationError;
@@ -1,129 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateMindMap = validateMindMap;
4
- exports.mindMapOutline = mindMapOutline;
5
- const idOk = (v) => typeof v === 'string' && /^[\w-]{1,80}$/.test(v);
6
- function validateMindMap(node) {
7
- const a = node.attrs;
8
- if (!a || ![1, 2, 3].includes(Number(a.formatVersion)) || !idOk(a.id) || !idOk(a.rootId) ||
9
- !['right', 'left', 'both', 'down'].includes(String(a.layout)) ||
10
- !['blue', 'teal', 'violet', 'amber'].includes(String(a.theme)) ||
11
- typeof a.height !== 'number' || !Number.isFinite(a.height) || a.height < 240 || a.height > 800) {
12
- throw new Error('思维导图属性或格式版本无效');
13
- }
14
- if (!Array.isArray(node.content) || node.content.length < 1 || node.content.filter(t => t?.type === 'mindMapTopic').length > 500 || node.content.length > 1500) {
15
- throw new Error('思维导图需要 1~500 个主题');
16
- }
17
- const ids = new Set();
18
- for (const t of node.content.filter(t => t?.type !== 'mindMapRelation')) {
19
- const p = t?.attrs;
20
- if (!t || t.type !== 'mindMapTopic' || !p || !idOk(p.id) || ids.has(p.id) ||
21
- typeof p.parentId !== 'string' || (p.parentId !== '' && !idOk(p.parentId)) ||
22
- typeof p.order !== 'number' || !Number.isFinite(p.order) || Math.abs(p.order) > 1e12 ||
23
- (t.content !== undefined && !Array.isArray(t.content)))
24
- throw new Error('思维导图主题结构无效');
25
- ids.add(p.id);
26
- for (const [key, values] of Object.entries({ shape: ['round', 'pill', 'text'], align: ['left', 'center', 'right'] })) {
27
- if (p[key] !== undefined && p[key] !== null && !values.includes(String(p[key])))
28
- throw new Error('导图主题样式无效');
29
- }
30
- for (const key of ['color', 'background'])
31
- if (p[key] && !['#18243a', '#ffffff', '#3864ef', '#087f8c', '#7950c7', '#a66b08', '#d94848', '#f3f5fb', '#dce7ff', '#d3f4e9', '#ece0ff', '#fff0c2', '#ffe1e1', '#233044'].includes(String(p[key])))
32
- throw new Error('导图颜色无效');
33
- if (p.fontSize !== undefined && p.fontSize !== null && ![12, 14, 16, 18, 20].includes(Number(p.fontSize)))
34
- throw new Error('导图字号无效');
35
- if (p.icon && !['💡', '🎯', '📌', '🚩', '⭐', '✅', '⚠️', '💬', '📅', '🔎'].includes(String(p.icon)))
36
- throw new Error('导图图标无效');
37
- if (p.done !== undefined && p.done !== null && typeof p.done !== 'boolean')
38
- throw new Error('导图状态无效');
39
- if (p.side !== undefined && p.side !== null && p.side !== -1 && p.side !== 1)
40
- throw new Error('导图分支方向无效');
41
- if (p.attachmentId && (typeof p.attachmentId !== 'string' || !/^[0-9a-f-]{36}$/i.test(p.attachmentId)))
42
- throw new Error('导图图片引用无效');
43
- let length = 0;
44
- const fields = new Set();
45
- let fieldsStarted = false, noteStarted = false;
46
- for (const c of t.content ?? []) {
47
- if (c && ['mindMapDescription', 'mindMapNote'].includes(c.type ?? '')) {
48
- if (c.type === 'mindMapDescription' && noteStarted)
49
- throw new Error('主题描述必须位于备注之前');
50
- fieldsStarted = true;
51
- if (c.type === 'mindMapNote')
52
- noteStarted = true;
53
- if (fields.has(c.type) || (c.content !== undefined && !Array.isArray(c.content)) || c.content?.some(n => n?.type !== 'text' || typeof n.text !== 'string' || n.content !== undefined) || (c.content ?? []).reduce((n, x) => n + (x.text?.length ?? 0), 0) > 4000)
54
- throw new Error('导图描述或备注无效');
55
- fields.add(c.type);
56
- continue;
57
- }
58
- if (!c || c.type !== 'text' || typeof c.text !== 'string' || c.content !== undefined) {
59
- throw new Error('思维导图主题只支持纯文本');
60
- }
61
- if (fieldsStarted)
62
- throw new Error('主题标题必须位于描述和备注之前');
63
- length += c.text.length;
64
- }
65
- if (length > 2000)
66
- throw new Error('单个主题文字不得超过 2000 字符');
67
- }
68
- if (!ids.has(a.rootId))
69
- throw new Error('思维导图缺少中心主题');
70
- if (a.branchStyle && !['curve', 'straight', 'step'].includes(String(a.branchStyle)))
71
- throw new Error('分支样式无效');
72
- const relationIds = new Set();
73
- for (const r of node.content.filter(t => t?.type === 'mindMapRelation')) {
74
- const p = r.attrs;
75
- if (!p || !idOk(p.id) || ids.has(p.id) || relationIds.has(p.id) || !idOk(p.source) || !idOk(p.target) || p.source === p.target ||
76
- !['related', 'depends', 'reference'].includes(String(p.kind)) || typeof p.label !== 'string' || p.label.length > 200 || r.content?.length)
77
- throw new Error('导图关系线无效');
78
- relationIds.add(p.id);
79
- }
80
- }
81
- /** Same deterministic tree projection as the reader; orphan/cycle conflicts never discard text. */
82
- function mindMapOutline(node) {
83
- const rootId = String(node.attrs?.rootId ?? '');
84
- if (!idOk(rootId) || !Array.isArray(node.content) || node.content.filter(t => t?.type === 'mindMapTopic').length > 500 || node.content.length > 1500)
85
- return [];
86
- const topics = (node.content ?? []).filter(t => t.type === 'mindMapTopic').map(t => ({
87
- id: String(t.attrs?.id ?? ''), parentId: String(t.attrs?.parentId ?? ''),
88
- order: Number(t.attrs?.order) || 0, text: (t.content ?? []).filter(c => c.type === 'text').map(c => c.text ?? '').join(''),
89
- ...Object.fromEntries((t.content ?? []).filter(c => c.type === 'mindMapDescription' || c.type === 'mindMapNote')
90
- .map(c => [c.type === 'mindMapDescription' ? 'description' : 'note', (c.content ?? []).map(n => n.text ?? '').join('')])),
91
- ...(t.attrs?.attachmentId ? { attachmentId: String(t.attrs.attachmentId) } : {}),
92
- }));
93
- if (!topics.some(t => t.id === rootId))
94
- return [];
95
- const byId = new Map(topics.map(t => [t.id, t]));
96
- for (const t of topics) {
97
- if (t.id === rootId)
98
- t.parentId = '';
99
- else if (!byId.has(t.parentId) || t.parentId === t.id)
100
- t.parentId = rootId;
101
- }
102
- for (const start of [...topics].sort((a, b) => a.id.localeCompare(b.id))) {
103
- const path = [], seen = new Set();
104
- let current = start;
105
- while (current && current.id !== rootId) {
106
- if (seen.has(current.id)) {
107
- byId.get(path.slice(path.indexOf(current.id)).sort()[0]).parentId = rootId;
108
- break;
109
- }
110
- path.push(current.id);
111
- seen.add(current.id);
112
- current = byId.get(current.parentId);
113
- }
114
- }
115
- topics.sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
116
- const result = [];
117
- const visited = new Set();
118
- const visit = (id, depth) => {
119
- const topic = byId.get(id);
120
- if (!topic || visited.has(id))
121
- return;
122
- visited.add(id);
123
- result.push({ ...topic, depth });
124
- for (const child of topics.filter(t => t.parentId === id))
125
- visit(child.id, depth + 1);
126
- };
127
- visit(rootId, 0);
128
- return result;
129
- }
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.validateMindMap=function validateMindMap(t){const e=t.attrs;if(!e||![1,2,3].includes(Number(e.formatVersion))||!idOk(e.id)||!idOk(e.rootId)||!["right","left","both","down"].includes(String(e.layout))||!["blue","teal","violet","amber"].includes(String(e.theme))||"number"!=typeof e.height||!Number.isFinite(e.height)||e.height<240||e.height>800)throw new Error("思维导图属性或格式版本无效");if(!Array.isArray(t.content)||t.content.length<1||t.content.filter(t=>"mindMapTopic"===t?.type).length>500||t.content.length>1500)throw new Error("思维导图需要 1~500 个主题");const r=new Set;for(const e of t.content.filter(t=>"mindMapRelation"!==t?.type)){const t=e?.attrs;if(!e||"mindMapTopic"!==e.type||!t||!idOk(t.id)||r.has(t.id)||"string"!=typeof t.parentId||""!==t.parentId&&!idOk(t.parentId)||"number"!=typeof t.order||!Number.isFinite(t.order)||Math.abs(t.order)>1e12||void 0!==e.content&&!Array.isArray(e.content))throw new Error("思维导图主题结构无效");r.add(t.id);for(const[e,r]of Object.entries({shape:["round","pill","text"],align:["left","center","right"]}))if(void 0!==t[e]&&null!==t[e]&&!r.includes(String(t[e])))throw new Error("导图主题样式无效");for(const e of["color","background"])if(t[e]&&!["#18243a","#ffffff","#3864ef","#087f8c","#7950c7","#a66b08","#d94848","#f3f5fb","#dce7ff","#d3f4e9","#ece0ff","#fff0c2","#ffe1e1","#233044"].includes(String(t[e])))throw new Error("导图颜色无效");if(void 0!==t.fontSize&&null!==t.fontSize&&![12,14,16,18,20].includes(Number(t.fontSize)))throw new Error("导图字号无效");if(t.icon&&!["💡","🎯","📌","🚩","⭐","✅","⚠️","💬","📅","🔎"].includes(String(t.icon)))throw new Error("导图图标无效");if(void 0!==t.done&&null!==t.done&&"boolean"!=typeof t.done)throw new Error("导图状态无效");if(void 0!==t.side&&null!==t.side&&-1!==t.side&&1!==t.side)throw new Error("导图分支方向无效");if(t.attachmentId&&("string"!=typeof t.attachmentId||!/^[0-9a-f-]{36}$/i.test(t.attachmentId)))throw new Error("导图图片引用无效");let n=0;const o=new Set;let i=!1,d=!1;for(const t of e.content??[])if(t&&["mindMapDescription","mindMapNote"].includes(t.type??"")){if("mindMapDescription"===t.type&&d)throw new Error("主题描述必须位于备注之前");if(i=!0,"mindMapNote"===t.type&&(d=!0),o.has(t.type)||void 0!==t.content&&!Array.isArray(t.content)||t.content?.some(t=>"text"!==t?.type||"string"!=typeof t.text||void 0!==t.content)||(t.content??[]).reduce((t,e)=>t+(e.text?.length??0),0)>4e3)throw new Error("导图描述或备注无效");o.add(t.type)}else{if(!t||"text"!==t.type||"string"!=typeof t.text||void 0!==t.content)throw new Error("思维导图主题只支持纯文本");if(i)throw new Error("主题标题必须位于描述和备注之前");n+=t.text.length}if(n>2e3)throw new Error("单个主题文字不得超过 2000 字符")}if(!r.has(e.rootId))throw new Error("思维导图缺少中心主题");if(e.branchStyle&&!["curve","straight","step"].includes(String(e.branchStyle)))throw new Error("分支样式无效");const n=new Set;for(const e of t.content.filter(t=>"mindMapRelation"===t?.type)){const t=e.attrs;if(!t||!idOk(t.id)||r.has(t.id)||n.has(t.id)||!idOk(t.source)||!idOk(t.target)||t.source===t.target||!["related","depends","reference"].includes(String(t.kind))||"string"!=typeof t.label||t.label.length>200||e.content?.length)throw new Error("导图关系线无效");n.add(t.id)}},exports.mindMapOutline=function mindMapOutline(t){const e=String(t.attrs?.rootId??"");if(!idOk(e)||!Array.isArray(t.content)||t.content.filter(t=>"mindMapTopic"===t?.type).length>500||t.content.length>1500)return[];const r=(t.content??[]).filter(t=>"mindMapTopic"===t.type).map(t=>({id:String(t.attrs?.id??""),parentId:String(t.attrs?.parentId??""),order:Number(t.attrs?.order)||0,text:(t.content??[]).filter(t=>"text"===t.type).map(t=>t.text??"").join(""),...Object.fromEntries((t.content??[]).filter(t=>"mindMapDescription"===t.type||"mindMapNote"===t.type).map(t=>["mindMapDescription"===t.type?"description":"note",(t.content??[]).map(t=>t.text??"").join("")])),...t.attrs?.attachmentId?{attachmentId:String(t.attrs.attachmentId)}:{}}));if(!r.some(t=>t.id===e))return[];const n=new Map(r.map(t=>[t.id,t]));for(const t of r)t.id===e?t.parentId="":n.has(t.parentId)&&t.parentId!==t.id||(t.parentId=e);for(const t of[...r].sort((t,e)=>t.id.localeCompare(e.id))){const r=[],o=new Set;let i=t;for(;i&&i.id!==e;){if(o.has(i.id)){n.get(r.slice(r.indexOf(i.id)).sort()[0]).parentId=e;break}r.push(i.id),o.add(i.id),i=n.get(i.parentId)}}r.sort((t,e)=>t.order-e.order||t.id.localeCompare(e.id));const o=[],i=new Set,visit=(t,e)=>{const d=n.get(t);if(d&&!i.has(t)){i.add(t),o.push({...d,depth:e});for(const n of r.filter(e=>e.parentId===t))visit(n.id,e+1)}};return visit(e,0),o};const idOk=t=>"string"==typeof t&&/^[\w-]{1,80}$/.test(t);
@@ -1,5 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONTENT_SCHEMA_VERSION = void 0;
4
- /** 协同握手与正文写入共用,不依赖 Nest 服务。 */
5
- exports.CONTENT_SCHEMA_VERSION = 10;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CONTENT_SCHEMA_VERSION=void 0,exports.CONTENT_SCHEMA_VERSION=10;