@file-viewer/core 2.0.11 → 2.1.1

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 (116) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/config/options.d.ts +1 -1
  4. package/dist/config/options.js +1 -1
  5. package/dist/contracts/types.d.ts +76 -1
  6. package/dist/headless.d.ts +3 -3
  7. package/dist/headless.js +2 -2
  8. package/dist/index.d.ts +10 -7
  9. package/dist/index.js +106 -49
  10. package/dist/lifecycle/operations.d.ts +1 -0
  11. package/dist/lifecycle/operations.js +65 -6
  12. package/dist/platform/assets.d.ts +3 -1
  13. package/dist/platform/assets.js +43 -6
  14. package/dist/registry/capabilities.d.ts +2 -2
  15. package/dist/registry/capabilities.js +2 -1
  16. package/dist/registry/formats.d.ts +20 -7
  17. package/dist/registry/formats.js +14 -5
  18. package/dist/registry/registry.d.ts +8 -1
  19. package/dist/registry/registry.js +29 -0
  20. package/dist/renderers/image.js +1 -10
  21. package/dist/renderers/index.d.ts +320 -2
  22. package/dist/renderers/index.js +27 -157
  23. package/dist/viewer/createViewer.js +86 -3
  24. package/package.json +17 -44
  25. package/dist/renderers/archive.d.ts +0 -2
  26. package/dist/renderers/archive.js +0 -547
  27. package/dist/renderers/archiveCache.d.ts +0 -10
  28. package/dist/renderers/archiveCache.js +0 -96
  29. package/dist/renderers/archiveFallback.d.ts +0 -7
  30. package/dist/renderers/archiveFallback.js +0 -166
  31. package/dist/renderers/archiveShared.d.ts +0 -23
  32. package/dist/renderers/archiveShared.js +0 -71
  33. package/dist/renderers/audio.d.ts +0 -8
  34. package/dist/renderers/audio.js +0 -219
  35. package/dist/renderers/cad.d.ts +0 -2
  36. package/dist/renderers/cad.js +0 -446
  37. package/dist/renderers/code.d.ts +0 -11
  38. package/dist/renderers/code.js +0 -233
  39. package/dist/renderers/data.d.ts +0 -7
  40. package/dist/renderers/data.js +0 -370
  41. package/dist/renderers/drawing.d.ts +0 -10
  42. package/dist/renderers/drawing.js +0 -882
  43. package/dist/renderers/eda.d.ts +0 -2
  44. package/dist/renderers/eda.js +0 -434
  45. package/dist/renderers/edaParser.d.ts +0 -77
  46. package/dist/renderers/edaParser.js +0 -569
  47. package/dist/renderers/email.d.ts +0 -2
  48. package/dist/renderers/email.js +0 -463
  49. package/dist/renderers/epub.d.ts +0 -2
  50. package/dist/renderers/epub.js +0 -331
  51. package/dist/renderers/geo.d.ts +0 -2
  52. package/dist/renderers/geo.js +0 -284
  53. package/dist/renderers/markdown.d.ts +0 -2
  54. package/dist/renderers/markdown.js +0 -83
  55. package/dist/renderers/model.d.ts +0 -2
  56. package/dist/renderers/model.js +0 -567
  57. package/dist/renderers/ofd.d.ts +0 -2
  58. package/dist/renderers/ofd.js +0 -256
  59. package/dist/renderers/openDocument.d.ts +0 -2
  60. package/dist/renderers/openDocument.js +0 -122
  61. package/dist/renderers/pdf.d.ts +0 -3
  62. package/dist/renderers/pdf.js +0 -1001
  63. package/dist/renderers/pdfStyles.d.ts +0 -1
  64. package/dist/renderers/pdfStyles.js +0 -1
  65. package/dist/renderers/pptx.d.ts +0 -2
  66. package/dist/renderers/pptx.js +0 -217
  67. package/dist/renderers/spreadsheet/state.d.ts +0 -80
  68. package/dist/renderers/spreadsheet/state.js +0 -96
  69. package/dist/renderers/spreadsheet/view.d.ts +0 -25
  70. package/dist/renderers/spreadsheet/view.js +0 -833
  71. package/dist/renderers/spreadsheet/worker/index.d.ts +0 -2
  72. package/dist/renderers/spreadsheet/worker/index.js +0 -1
  73. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.d.ts +0 -73
  74. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.js +0 -623
  75. package/dist/renderers/spreadsheet/worker/sheetjs/color.d.ts +0 -2
  76. package/dist/renderers/spreadsheet/worker/sheetjs/color.js +0 -73
  77. package/dist/renderers/spreadsheet/worker/sheetjs/index.d.ts +0 -1
  78. package/dist/renderers/spreadsheet/worker/sheetjs/index.js +0 -1
  79. package/dist/renderers/spreadsheet/worker/sheetjs/parser.d.ts +0 -18
  80. package/dist/renderers/spreadsheet/worker/sheetjs/parser.js +0 -106
  81. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.d.ts +0 -1
  82. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.js +0 -11
  83. package/dist/renderers/spreadsheet/worker/type.d.ts +0 -57
  84. package/dist/renderers/spreadsheet/worker/type.js +0 -1
  85. package/dist/renderers/spreadsheet.d.ts +0 -3
  86. package/dist/renderers/spreadsheet.js +0 -929
  87. package/dist/renderers/typst.d.ts +0 -8
  88. package/dist/renderers/typst.js +0 -547
  89. package/dist/renderers/umd/parser.d.ts +0 -30
  90. package/dist/renderers/umd/parser.js +0 -408
  91. package/dist/renderers/umd.d.ts +0 -2
  92. package/dist/renderers/umd.js +0 -297
  93. package/dist/renderers/video.d.ts +0 -8
  94. package/dist/renderers/video.js +0 -108
  95. package/dist/renderers/wordDoc.d.ts +0 -5
  96. package/dist/renderers/wordDoc.js +0 -284
  97. package/dist/renderers/wordDocx.d.ts +0 -5
  98. package/dist/renderers/wordDocx.js +0 -985
  99. package/dist/renderers/wordDocx.worker.d.ts +0 -1
  100. package/dist/renderers/wordDocx.worker.js +0 -96
  101. package/vendor/ofd/dltech/jbig2/arithmetic_decoder.js +0 -183
  102. package/vendor/ofd/dltech/jbig2/ccitt.js +0 -1070
  103. package/vendor/ofd/dltech/jbig2/compatibility.js +0 -12
  104. package/vendor/ofd/dltech/jbig2/core_utils.js +0 -180
  105. package/vendor/ofd/dltech/jbig2/is_node.js +0 -27
  106. package/vendor/ofd/dltech/jbig2/jbig2.js +0 -2589
  107. package/vendor/ofd/dltech/jbig2/jbig2_stream.js +0 -81
  108. package/vendor/ofd/dltech/jbig2/primitives.js +0 -387
  109. package/vendor/ofd/dltech/jbig2/stream.js +0 -1348
  110. package/vendor/ofd/dltech/jbig2/util.js +0 -972
  111. package/vendor/ofd/dltech/ofd/ofd.d.ts +0 -11
  112. package/vendor/ofd/dltech/ofd/ofd.js +0 -100
  113. package/vendor/ofd/dltech/ofd/ofd_parser.js +0 -395
  114. package/vendor/ofd/dltech/ofd/ofd_render.js +0 -473
  115. package/vendor/ofd/dltech/ofd/ofd_util.js +0 -350
  116. package/vendor/ofd/dltech/ofd/pipeline.js +0 -26
@@ -1,569 +0,0 @@
1
- const CFB_MAGIC = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1];
2
- const MAX_STREAMS = 200;
3
- const MAX_SAMPLE_BYTES = 4096;
4
- const MAX_HEX_BYTES = 192;
5
- const MAX_STRINGS = 180;
6
- const MAX_STREAM_STRINGS = 24;
7
- const MAX_PROPERTIES = 420;
8
- const toBytes = (buffer) => new Uint8Array(buffer);
9
- const isCfbFile = (bytes) => {
10
- return CFB_MAGIC.every((value, index) => bytes[index] === value);
11
- };
12
- const normalizeBytes = (value) => {
13
- return value instanceof Uint8Array ? value : new Uint8Array(value);
14
- };
15
- const cleanupText = (text) => {
16
- return text
17
- .replace(/\u0000/g, '')
18
- .replace(/[^\S\r\n]+/g, ' ')
19
- .replace(/\r\n/g, '\n')
20
- .trim();
21
- };
22
- const normalizeSearchText = (value) => {
23
- return cleanupText(value).toLowerCase();
24
- };
25
- const lastPathPart = (path) => {
26
- const parts = path.split('/').filter(Boolean);
27
- return parts[parts.length - 1] || path || '/';
28
- };
29
- const stripExtension = (value) => {
30
- return value.replace(/\.[a-z0-9]+$/i, '');
31
- };
32
- const uniquePush = (target, value, max = Number.POSITIVE_INFINITY) => {
33
- const cleaned = cleanupText(value);
34
- if (!cleaned || target.includes(cleaned) || target.length >= max) {
35
- return;
36
- }
37
- target.push(cleaned);
38
- };
39
- const looksLikeText = (bytes) => {
40
- if (!bytes.length) {
41
- return false;
42
- }
43
- const sample = bytes.slice(0, Math.min(bytes.length, MAX_SAMPLE_BYTES));
44
- let printable = 0;
45
- let zeroBytes = 0;
46
- for (const byte of sample) {
47
- if (byte === 0) {
48
- zeroBytes += 1;
49
- }
50
- if (byte === 9 || byte === 10 || byte === 13 || (byte >= 32 && byte <= 126) || byte >= 0x80) {
51
- printable += 1;
52
- }
53
- }
54
- return printable / sample.length > 0.82 || zeroBytes / sample.length > 0.25;
55
- };
56
- const decodeSample = (bytes) => {
57
- const sample = bytes.slice(0, Math.min(bytes.length, MAX_SAMPLE_BYTES));
58
- if (!sample.length) {
59
- return '';
60
- }
61
- try {
62
- let zeroOdd = 0;
63
- let zeroEven = 0;
64
- for (let index = 0; index < sample.length; index += 1) {
65
- if (sample[index] !== 0) {
66
- continue;
67
- }
68
- if (index % 2 === 0) {
69
- zeroEven += 1;
70
- }
71
- else {
72
- zeroOdd += 1;
73
- }
74
- }
75
- const decoder = zeroOdd > sample.length / 5 && zeroOdd > zeroEven * 2
76
- ? new TextDecoder('utf-16le', { fatal: false })
77
- : new TextDecoder('utf-8', { fatal: false });
78
- return cleanupText(decoder.decode(sample));
79
- }
80
- catch {
81
- return '';
82
- }
83
- };
84
- const hexPreview = (bytes) => {
85
- const sample = bytes.slice(0, Math.min(bytes.length, MAX_HEX_BYTES));
86
- const lines = [];
87
- for (let offset = 0; offset < sample.length; offset += 16) {
88
- const row = sample.slice(offset, offset + 16);
89
- const hex = Array.from(row).map(byte => byte.toString(16).padStart(2, '0')).join(' ');
90
- const ascii = Array.from(row)
91
- .map(byte => byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.')
92
- .join('');
93
- lines.push(`${offset.toString(16).padStart(8, '0')} ${hex.padEnd(47)} ${ascii}`);
94
- }
95
- return lines.join('\n');
96
- };
97
- const extractAsciiStrings = (bytes) => {
98
- const result = [];
99
- let current = '';
100
- for (const byte of bytes) {
101
- if (byte >= 32 && byte <= 126) {
102
- current += String.fromCharCode(byte);
103
- continue;
104
- }
105
- if (current.length >= 4) {
106
- result.push(current);
107
- }
108
- current = '';
109
- }
110
- if (current.length >= 4) {
111
- result.push(current);
112
- }
113
- return result;
114
- };
115
- const extractUtf16Strings = (bytes) => {
116
- const result = [];
117
- let current = '';
118
- for (let index = 0; index + 1 < bytes.length; index += 2) {
119
- const low = bytes[index];
120
- const high = bytes[index + 1];
121
- if (high === 0 && low >= 32 && low <= 126) {
122
- current += String.fromCharCode(low);
123
- continue;
124
- }
125
- if (current.length >= 4) {
126
- result.push(current);
127
- }
128
- current = '';
129
- }
130
- if (current.length >= 4) {
131
- result.push(current);
132
- }
133
- return result;
134
- };
135
- const collectStrings = (chunks, maxStrings = MAX_STRINGS) => {
136
- const seen = new Set();
137
- const result = [];
138
- chunks.forEach(chunk => {
139
- const candidates = [...extractAsciiStrings(chunk), ...extractUtf16Strings(chunk)];
140
- candidates.forEach(item => {
141
- const cleaned = cleanupText(item);
142
- if (!cleaned || cleaned.length < 4 || seen.has(cleaned) || result.length >= maxStrings) {
143
- return;
144
- }
145
- seen.add(cleaned);
146
- result.push(cleaned);
147
- });
148
- });
149
- return result;
150
- };
151
- const PROPERTY_RE = /^\s*([A-Za-z][A-Za-z0-9_. /#-]{1,56})\s*[:=]\s*(.{1,240})\s*$/;
152
- const INLINE_PROPERTY_RE = /\b([A-Za-z][A-Za-z0-9_. /#-]{1,56})\s*=\s*([^;\n\r|]{1,240})/g;
153
- const normalizePropertyKey = (key) => {
154
- return cleanupText(key).replace(/\s+/g, ' ');
155
- };
156
- const addProperty = (target, seen, key, value, source) => {
157
- if (target.length >= MAX_PROPERTIES) {
158
- return;
159
- }
160
- const normalizedKey = normalizePropertyKey(key);
161
- const normalizedValue = cleanupText(value);
162
- if (!normalizedKey || !normalizedValue) {
163
- return;
164
- }
165
- const identity = `${source}\u0000${normalizedKey.toLowerCase()}\u0000${normalizedValue}`;
166
- if (seen.has(identity)) {
167
- return;
168
- }
169
- seen.add(identity);
170
- target.push({ key: normalizedKey, value: normalizedValue, source });
171
- };
172
- const extractProperties = (text, strings, source) => {
173
- const properties = [];
174
- const seen = new Set();
175
- const chunks = [text, ...strings].filter(Boolean);
176
- chunks.forEach(chunk => {
177
- cleanupText(chunk)
178
- .split(/\n|[|;]/)
179
- .forEach(line => {
180
- const match = line.match(PROPERTY_RE);
181
- if (match) {
182
- addProperty(properties, seen, match[1], match[2], source);
183
- }
184
- });
185
- for (const match of chunk.matchAll(INLINE_PROPERTY_RE)) {
186
- addProperty(properties, seen, match[1], match[2], source);
187
- }
188
- });
189
- return properties;
190
- };
191
- const hasProperty = (properties, keys) => {
192
- const normalized = keys.map(key => key.toLowerCase());
193
- return properties.some(property => normalized.includes(property.key.toLowerCase()));
194
- };
195
- const getPropertyValue = (properties, keys) => {
196
- var _a;
197
- const normalized = keys.map(key => key.toLowerCase());
198
- return (_a = properties.find(property => normalized.includes(property.key.toLowerCase()))) === null || _a === void 0 ? void 0 : _a.value;
199
- };
200
- const roleFromText = (type, path, name, sample, strings, properties, kind) => {
201
- const haystack = normalizeSearchText(`${path}\n${name}\n${sample}\n${strings.join('\n')}`);
202
- if (haystack === '/' || path === '/') {
203
- return 'root';
204
- }
205
- if (kind === 'storage' && /(^|\/)(library|libraries)(\/|$)/i.test(path)) {
206
- return 'library';
207
- }
208
- if (/(header|version|source|author|metadata|property|properties)/.test(haystack)) {
209
- return hasProperty(properties, ['Name', 'Pins', 'Footprint', 'Padstack']) ? 'property' : 'metadata';
210
- }
211
- if (type === 'olb') {
212
- if (/(^|\/)(symbols?|parts?)(\/|$)/.test(haystack) || hasProperty(properties, ['Pins', 'Footprint', 'PCB Footprint', 'Part Number'])) {
213
- return 'symbol';
214
- }
215
- if (/(^|\/)(library|capture|orcad)(\/|$)/.test(haystack)) {
216
- return 'library';
217
- }
218
- }
219
- if (type === 'dra') {
220
- if (/(padstack|pad stack|thermal|antipad|drill)/.test(haystack) || hasProperty(properties, ['Padstack', 'Drill'])) {
221
- return 'padstack';
222
- }
223
- if (/(footprint|package|psm|bsm|fsm|ssm|symbol)/.test(haystack)) {
224
- return 'footprint';
225
- }
226
- if (/(route|net|via|ratsnest)/.test(haystack)) {
227
- return 'net';
228
- }
229
- if (/(line |arc |circle|shape|outline|silk|place_bound|assembly|soldermask|pastemask)/.test(haystack)) {
230
- return 'geometry';
231
- }
232
- if (/(drawing|units|layers?|constraint|allegro)/.test(haystack) || hasProperty(properties, ['Units', 'Layers'])) {
233
- return 'drawing';
234
- }
235
- }
236
- if (properties.length) {
237
- return 'property';
238
- }
239
- return kind === 'storage' ? 'library' : 'unknown';
240
- };
241
- const buildStreamView = (type, path, name, size, kind, bytes) => {
242
- if (kind === 'storage' || !bytes) {
243
- const role = roleFromText(type, path, name, '', [], [], kind);
244
- return { path, name, size, kind, role, strings: [], properties: [] };
245
- }
246
- const sample = looksLikeText(bytes) ? decodeSample(bytes) : '';
247
- const strings = collectStrings([bytes], MAX_STREAM_STRINGS);
248
- const properties = extractProperties(sample, strings, path);
249
- const role = roleFromText(type, path, name, sample, strings, properties, sample ? 'text' : 'binary');
250
- return {
251
- path,
252
- name,
253
- size,
254
- kind: sample ? 'text' : 'binary',
255
- role,
256
- sample,
257
- hex: sample ? undefined : hexPreview(bytes),
258
- strings,
259
- properties
260
- };
261
- };
262
- const sortTree = (node) => {
263
- node.children.sort((left, right) => {
264
- if (left.children.length !== right.children.length) {
265
- return right.children.length - left.children.length;
266
- }
267
- return left.name.localeCompare(right.name);
268
- });
269
- node.children.forEach(sortTree);
270
- };
271
- const buildTree = (streams, type) => {
272
- const root = {
273
- id: `${type}:root`,
274
- path: '/',
275
- name: type.toUpperCase(),
276
- kind: 'storage',
277
- role: 'root',
278
- size: 0,
279
- children: []
280
- };
281
- const nodes = new Map([['/', root]]);
282
- streams.forEach(stream => {
283
- const parts = stream.path.split('/').filter(Boolean);
284
- let parent = root;
285
- let currentPath = '';
286
- parts.forEach((part, index) => {
287
- currentPath += `/${part}`;
288
- const isLeaf = index === parts.length - 1;
289
- let node = nodes.get(currentPath);
290
- if (!node) {
291
- node = {
292
- id: `${type}:${currentPath}`,
293
- path: currentPath,
294
- name: part,
295
- kind: isLeaf ? stream.kind : 'storage',
296
- role: isLeaf ? stream.role : roleFromText(type, currentPath, part, '', [], [], 'storage'),
297
- size: isLeaf ? stream.size : 0,
298
- children: []
299
- };
300
- nodes.set(currentPath, node);
301
- parent.children.push(node);
302
- }
303
- if (isLeaf) {
304
- node.kind = stream.kind;
305
- node.role = stream.role;
306
- node.size = stream.size;
307
- }
308
- parent = node;
309
- });
310
- });
311
- sortTree(root);
312
- return root.children;
313
- };
314
- const splitListValue = (value) => {
315
- if (!value) {
316
- return [];
317
- }
318
- const result = [];
319
- value.split(/[,/;| ]+/).forEach(item => {
320
- if (/^[A-Za-z0-9_.+-]+$/.test(item)) {
321
- uniquePush(result, item, 64);
322
- }
323
- });
324
- return result;
325
- };
326
- const entityRoleForStream = (stream, type) => {
327
- if (type === 'olb') {
328
- return stream.role === 'symbol' && stream.kind !== 'storage' ? 'symbol' : null;
329
- }
330
- if (stream.role === 'padstack') {
331
- return 'padstack';
332
- }
333
- if (stream.role === 'footprint' || (stream.role === 'geometry' && /\/footprint\//i.test(stream.path))) {
334
- return 'footprint';
335
- }
336
- if (stream.role === 'drawing') {
337
- return 'drawing';
338
- }
339
- return null;
340
- };
341
- const streamEntityPath = (stream, role) => {
342
- if (role === 'footprint') {
343
- const match = stream.path.match(/^(.+?\/Footprint)(?:\/|$)/i);
344
- return (match === null || match === void 0 ? void 0 : match[1]) || stream.path;
345
- }
346
- if (role === 'drawing') {
347
- const match = stream.path.match(/^(.+?\/Drawing)(?:\/|$)/i);
348
- return (match === null || match === void 0 ? void 0 : match[1]) || stream.path;
349
- }
350
- return stream.path;
351
- };
352
- const inferEntityName = (stream, role, entityPath) => {
353
- const propertyName = getPropertyValue(stream.properties, [
354
- 'Name',
355
- 'Part',
356
- 'Part Name',
357
- 'Symbol',
358
- 'Device',
359
- 'Footprint',
360
- 'PCB Footprint',
361
- 'Package',
362
- 'Padstack',
363
- 'Pad Stack',
364
- 'Drawing'
365
- ]);
366
- if (propertyName) {
367
- return propertyName;
368
- }
369
- const pathName = stripExtension(lastPathPart(entityPath));
370
- if (pathName && pathName !== '/') {
371
- return pathName;
372
- }
373
- return role.toUpperCase();
374
- };
375
- const roleKeywords = (stream, role) => {
376
- const keywords = [];
377
- const text = `${stream.path}\n${stream.sample || ''}\n${stream.strings.join('\n')}`.toLowerCase();
378
- const domainWords = role === 'symbol'
379
- ? ['pins', 'footprint', 'pspice', 'part', 'symbol']
380
- : ['units', 'layers', 'padstack', 'drill', 'outline', 'route', 'constraint', 'shape', 'place_bound'];
381
- domainWords.forEach(word => {
382
- if (text.includes(word)) {
383
- uniquePush(keywords, word, 12);
384
- }
385
- });
386
- return keywords;
387
- };
388
- const appendUniqueProperties = (target, properties) => {
389
- const seen = new Set(target.map(property => `${property.key.toLowerCase()}\u0000${property.value}`));
390
- properties.forEach(property => {
391
- const identity = `${property.key.toLowerCase()}\u0000${property.value}`;
392
- if (seen.has(identity)) {
393
- return;
394
- }
395
- seen.add(identity);
396
- target.push(property);
397
- });
398
- };
399
- const collectEntities = (streams, type) => {
400
- const entities = new Map();
401
- streams.forEach(stream => {
402
- const role = entityRoleForStream(stream, type);
403
- if (!role) {
404
- return;
405
- }
406
- const entityPath = streamEntityPath(stream, role);
407
- const key = `${role}:${entityPath.toLowerCase()}`;
408
- const existing = entities.get(key);
409
- const entity = existing || {
410
- id: key,
411
- name: inferEntityName(stream, role, entityPath),
412
- role,
413
- path: entityPath,
414
- streamCount: 0,
415
- byteLength: 0,
416
- properties: [],
417
- pins: [],
418
- layers: [],
419
- keywords: []
420
- };
421
- entity.streamCount += 1;
422
- entity.byteLength += stream.size;
423
- appendUniqueProperties(entity.properties, stream.properties);
424
- splitListValue(getPropertyValue(stream.properties, ['Pins', 'Pin', 'Pin Numbers'])).forEach(pin => uniquePush(entity.pins, pin, 96));
425
- splitListValue(getPropertyValue(stream.properties, ['Layers', 'Layer'])).forEach(layer => uniquePush(entity.layers, layer, 64));
426
- roleKeywords(stream, role).forEach(keyword => uniquePush(entity.keywords, keyword, 16));
427
- entity.description || (entity.description = getPropertyValue(entity.properties, ['Description', 'Desc']));
428
- entity.footprint || (entity.footprint = getPropertyValue(entity.properties, ['Footprint', 'PCB Footprint', 'Package']));
429
- entities.set(key, entity);
430
- });
431
- return Array.from(entities.values()).sort((left, right) => {
432
- var _a, _b;
433
- const roleOrder = { symbol: 0, footprint: 1, padstack: 2, drawing: 3 };
434
- const order = ((_a = roleOrder[left.role]) !== null && _a !== void 0 ? _a : 9) - ((_b = roleOrder[right.role]) !== null && _b !== void 0 ? _b : 9);
435
- return order || left.name.localeCompare(right.name);
436
- });
437
- };
438
- const collectMetadata = (streams) => {
439
- const metadata = [];
440
- streams.forEach(stream => {
441
- if (stream.role === 'metadata' || stream.role === 'library' || stream.role === 'drawing') {
442
- appendUniqueProperties(metadata, stream.properties);
443
- }
444
- });
445
- return metadata.slice(0, 80);
446
- };
447
- const buildStats = (streams, entities, strings, parser) => {
448
- const stats = {
449
- textStreams: streams.filter(stream => stream.kind === 'text').length,
450
- binaryStreams: streams.filter(stream => stream.kind === 'binary').length,
451
- storageEntries: streams.filter(stream => stream.kind === 'storage').length,
452
- propertyCount: streams.reduce((sum, stream) => sum + stream.properties.length, 0),
453
- stringCount: strings.length,
454
- symbolCount: entities.filter(entity => entity.role === 'symbol').length,
455
- footprintCount: entities.filter(entity => entity.role === 'footprint').length,
456
- padstackCount: entities.filter(entity => entity.role === 'padstack').length,
457
- confidence: 'low'
458
- };
459
- if (parser === 'cfb' && entities.length && stats.propertyCount) {
460
- stats.confidence = 'high';
461
- }
462
- else if (parser === 'cfb' || strings.length || stats.propertyCount) {
463
- stats.confidence = 'medium';
464
- }
465
- return stats;
466
- };
467
- const buildDiagnostics = (type, parser, streams, entities, strings, warnings) => {
468
- const diagnostics = warnings.map((message, index) => ({
469
- level: 'warning',
470
- code: `warning-${index + 1}`,
471
- message
472
- }));
473
- diagnostics.push({
474
- level: 'info',
475
- code: 'parser',
476
- message: parser === 'cfb'
477
- ? '已识别为 Microsoft Compound File / OLE2 复合文档容器,并在浏览器端解析目录与流。'
478
- : '未识别为 CFB 容器,已使用二进制字符串索引模式展示可读信息。'
479
- });
480
- diagnostics.push({
481
- level: 'info',
482
- code: 'coverage',
483
- message: `已索引 ${streams.length} 个条目、${strings.length} 个可读字符串、${entities.length} 个 EDA 结构候选。`
484
- });
485
- const needsSymbol = type === 'olb' && !entities.some(entity => entity.role === 'symbol');
486
- const needsFootprint = type === 'dra' && !entities.some(entity => entity.role === 'footprint' || entity.role === 'padstack');
487
- if (needsSymbol || needsFootprint) {
488
- diagnostics.push({
489
- level: 'warning',
490
- code: 'domain-candidates',
491
- message: type === 'olb'
492
- ? '未发现明确的元件符号候选,文件可能使用了私有二进制编码或需要专业工具导出 ASCII/XML 后再检查。'
493
- : '未发现明确的封装、图形或 padstack 候选,文件可能使用了私有二进制数据库编码。'
494
- });
495
- }
496
- return diagnostics;
497
- };
498
- const assembleResult = (buffer, type, parser, streamCount, streams, strings, warnings) => {
499
- const totalStreamBytes = streams.reduce((sum, stream) => sum + stream.size, 0);
500
- const entities = collectEntities(streams, type);
501
- const metadata = collectMetadata(streams);
502
- const diagnostics = buildDiagnostics(type, parser, streams, entities, strings, warnings);
503
- return {
504
- type,
505
- parser,
506
- title: type === 'olb'
507
- ? (parser === 'cfb' ? 'OrCAD Capture Symbol Library' : 'OLB Binary Library')
508
- : (parser === 'cfb' ? 'OrCAD / Allegro Drawing Library' : 'DRA Binary Drawing'),
509
- byteLength: buffer.byteLength,
510
- streamCount,
511
- totalStreamBytes,
512
- streams,
513
- tree: buildTree(streams, type),
514
- entities,
515
- metadata,
516
- strings,
517
- warnings,
518
- diagnostics,
519
- stats: buildStats(streams, entities, strings, parser)
520
- };
521
- };
522
- const parseCfbContainer = async (buffer, type) => {
523
- const CFB = await import('cfb');
524
- const container = CFB.parse(toBytes(buffer), { type: 'array' });
525
- const streamEntries = container.FileIndex
526
- .map((entry, index) => ({ entry, path: container.FullPaths[index] || entry.name }))
527
- .filter(item => item.entry.type !== 5 && item.path !== '/' && item.entry.name)
528
- .slice(0, MAX_STREAMS);
529
- const byteChunks = [];
530
- const streams = streamEntries.map(({ entry, path }) => {
531
- if (entry.type === 1) {
532
- return buildStreamView(type, path, entry.name, entry.size || 0, 'storage');
533
- }
534
- const content = normalizeBytes(entry.content || []);
535
- byteChunks.push(content);
536
- return buildStreamView(type, path, entry.name, entry.size || content.byteLength || 0, 'binary', content);
537
- });
538
- const warnings = streamEntries.length >= MAX_STREAMS
539
- ? [`仅展示前 ${MAX_STREAMS} 个 CFB 项,完整文件仍可下载后在专业 EDA 工具中打开。`]
540
- : [];
541
- return assembleResult(buffer, type, 'cfb', container.FileIndex.length, streams, collectStrings(byteChunks), warnings);
542
- };
543
- const parseBinaryFallback = (buffer, type) => {
544
- const bytes = toBytes(buffer);
545
- const stream = buildStreamView(type, `${type}.${type}`, `${type}.${type}`, buffer.byteLength, 'binary', bytes);
546
- return assembleResult(buffer, type, 'binary', 1, [stream], collectStrings([bytes]), [
547
- '该文件不是标准 CFB 容器,已退化为安全的二进制字符串索引预览。'
548
- ]);
549
- };
550
- export const parseEdaFile = async (buffer, type = 'olb') => {
551
- const normalizedType = type === 'dra' ? 'dra' : 'olb';
552
- const bytes = toBytes(buffer);
553
- if (!isCfbFile(bytes)) {
554
- return parseBinaryFallback(buffer, normalizedType);
555
- }
556
- try {
557
- return await parseCfbContainer(buffer, normalizedType);
558
- }
559
- catch (error) {
560
- const fallback = parseBinaryFallback(buffer, normalizedType);
561
- fallback.warnings.unshift(error instanceof Error ? error.message : String(error));
562
- fallback.diagnostics.unshift({
563
- level: 'warning',
564
- code: 'cfb-parse-failed',
565
- message: error instanceof Error ? error.message : String(error)
566
- });
567
- return fallback;
568
- }
569
- };
@@ -1,2 +0,0 @@
1
- import type { FileRenderContext, FileViewerRenderedInstance } from '../contracts/types';
2
- export default function renderEmail(buffer: ArrayBuffer, target: HTMLDivElement, type?: string, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;