ts-visio 1.0.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 +21 -0
- package/README.md +343 -0
- package/dist/Layer.d.ts +12 -0
- package/dist/Layer.js +35 -0
- package/dist/Page.d.ts +30 -0
- package/dist/Page.js +169 -0
- package/dist/PageManager.d.ts +8 -0
- package/dist/PageManager.js +35 -0
- package/dist/SchemaDiagram.d.ts +22 -0
- package/dist/SchemaDiagram.js +36 -0
- package/dist/Shape.d.ts +68 -0
- package/dist/Shape.js +203 -0
- package/dist/ShapeModifier.d.ts +66 -0
- package/dist/ShapeModifier.js +889 -0
- package/dist/ShapeReader.d.ts +9 -0
- package/dist/ShapeReader.js +51 -0
- package/dist/VisioDocument.d.ts +21 -0
- package/dist/VisioDocument.js +119 -0
- package/dist/VisioPackage.d.ts +10 -0
- package/dist/VisioPackage.js +112 -0
- package/dist/core/MasterManager.d.ts +15 -0
- package/dist/core/MasterManager.js +43 -0
- package/dist/core/MediaConstants.d.ts +5 -0
- package/dist/core/MediaConstants.js +16 -0
- package/dist/core/MediaManager.d.ts +13 -0
- package/dist/core/MediaManager.js +88 -0
- package/dist/core/PageManager.d.ts +28 -0
- package/dist/core/PageManager.js +244 -0
- package/dist/core/RelsManager.d.ts +11 -0
- package/dist/core/RelsManager.js +81 -0
- package/dist/core/VisioConstants.d.ts +38 -0
- package/dist/core/VisioConstants.js +41 -0
- package/dist/core/VisioValidator.d.ts +27 -0
- package/dist/core/VisioValidator.js +362 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +32 -0
- package/dist/shapes/ConnectorBuilder.d.ts +37 -0
- package/dist/shapes/ConnectorBuilder.js +173 -0
- package/dist/shapes/ContainerBuilder.d.ts +6 -0
- package/dist/shapes/ContainerBuilder.js +103 -0
- package/dist/shapes/ForeignShapeBuilder.d.ts +4 -0
- package/dist/shapes/ForeignShapeBuilder.js +47 -0
- package/dist/shapes/ShapeBuilder.d.ts +4 -0
- package/dist/shapes/ShapeBuilder.js +68 -0
- package/dist/templates/MinimalVsdx.d.ts +10 -0
- package/dist/templates/MinimalVsdx.js +66 -0
- package/dist/types/VisioTypes.d.ts +85 -0
- package/dist/types/VisioTypes.js +14 -0
- package/dist/utils/StubHelpers.d.ts +7 -0
- package/dist/utils/StubHelpers.js +16 -0
- package/dist/utils/StyleHelpers.d.ts +30 -0
- package/dist/utils/StyleHelpers.js +95 -0
- package/dist/utils/VisioParsers.d.ts +6 -0
- package/dist/utils/VisioParsers.js +45 -0
- package/package.json +27 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { VisioPackage } from './VisioPackage';
|
|
2
|
+
import { VisioShape } from './types/VisioTypes';
|
|
3
|
+
export declare class ShapeReader {
|
|
4
|
+
private pkg;
|
|
5
|
+
private parser;
|
|
6
|
+
constructor(pkg: VisioPackage);
|
|
7
|
+
readShapes(path: string): VisioShape[];
|
|
8
|
+
private parseShape;
|
|
9
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ShapeReader = void 0;
|
|
4
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
5
|
+
const VisioParsers_1 = require("./utils/VisioParsers");
|
|
6
|
+
class ShapeReader {
|
|
7
|
+
constructor(pkg) {
|
|
8
|
+
this.pkg = pkg;
|
|
9
|
+
this.parser = new fast_xml_parser_1.XMLParser({
|
|
10
|
+
ignoreAttributes: false,
|
|
11
|
+
attributeNamePrefix: "@_"
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
readShapes(path) {
|
|
15
|
+
let content;
|
|
16
|
+
try {
|
|
17
|
+
content = this.pkg.getFileText(path);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const parsed = this.parser.parse(content);
|
|
23
|
+
// Supports PageContents -> Shapes -> Shape or just Shapes -> Shape depending on structure
|
|
24
|
+
const shapesData = parsed.PageContents?.Shapes?.Shape;
|
|
25
|
+
if (!shapesData)
|
|
26
|
+
return [];
|
|
27
|
+
const shapesArray = (0, VisioParsers_1.asArray)(shapesData);
|
|
28
|
+
return shapesArray.map(s => this.parseShape(s));
|
|
29
|
+
}
|
|
30
|
+
parseShape(s) {
|
|
31
|
+
const shape = {
|
|
32
|
+
ID: s['@_ID'],
|
|
33
|
+
Name: s['@_Name'],
|
|
34
|
+
NameU: s['@_NameU'],
|
|
35
|
+
Type: s['@_Type'],
|
|
36
|
+
Master: s['@_Master'],
|
|
37
|
+
Text: s.Text?.['#text'] || (typeof s.Text === 'string' ? s.Text : undefined),
|
|
38
|
+
Cells: (0, VisioParsers_1.parseCells)(s),
|
|
39
|
+
Sections: {}
|
|
40
|
+
};
|
|
41
|
+
const sections = (0, VisioParsers_1.asArray)(s.Section);
|
|
42
|
+
for (const sec of sections) {
|
|
43
|
+
const section = sec;
|
|
44
|
+
if (section['@_N']) {
|
|
45
|
+
shape.Sections[section['@_N']] = (0, VisioParsers_1.parseSection)(section);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return shape;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.ShapeReader = ShapeReader;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Page } from './Page';
|
|
2
|
+
export declare class VisioDocument {
|
|
3
|
+
private pkg;
|
|
4
|
+
private pageManager;
|
|
5
|
+
private _pageCache;
|
|
6
|
+
private mediaManager;
|
|
7
|
+
private constructor();
|
|
8
|
+
static create(): Promise<VisioDocument>;
|
|
9
|
+
static load(pathOrBuffer: string | Buffer | ArrayBuffer | Uint8Array): Promise<VisioDocument>;
|
|
10
|
+
addPage(name: string): Promise<Page>;
|
|
11
|
+
get pages(): Page[];
|
|
12
|
+
/**
|
|
13
|
+
* Add a background page to the document
|
|
14
|
+
*/
|
|
15
|
+
addBackgroundPage(name: string): Promise<Page>;
|
|
16
|
+
/**
|
|
17
|
+
* Set a background page for a foreground page
|
|
18
|
+
*/
|
|
19
|
+
setBackgroundPage(foregroundPage: Page, backgroundPage: Page): Promise<void>;
|
|
20
|
+
save(filename?: string): Promise<Buffer>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.VisioDocument = void 0;
|
|
37
|
+
const VisioPackage_1 = require("./VisioPackage");
|
|
38
|
+
const PageManager_1 = require("./core/PageManager");
|
|
39
|
+
const Page_1 = require("./Page");
|
|
40
|
+
const MediaManager_1 = require("./core/MediaManager");
|
|
41
|
+
class VisioDocument {
|
|
42
|
+
constructor(pkg) {
|
|
43
|
+
this.pkg = pkg;
|
|
44
|
+
this._pageCache = null;
|
|
45
|
+
this.pageManager = new PageManager_1.PageManager(pkg);
|
|
46
|
+
this.mediaManager = new MediaManager_1.MediaManager(pkg);
|
|
47
|
+
}
|
|
48
|
+
static async create() {
|
|
49
|
+
const pkg = await VisioPackage_1.VisioPackage.create();
|
|
50
|
+
return new VisioDocument(pkg);
|
|
51
|
+
}
|
|
52
|
+
static async load(pathOrBuffer) {
|
|
53
|
+
const pkg = new VisioPackage_1.VisioPackage();
|
|
54
|
+
if (typeof pathOrBuffer === 'string') {
|
|
55
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
|
|
56
|
+
const buffer = await fs.readFile(pathOrBuffer);
|
|
57
|
+
await pkg.load(buffer);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
await pkg.load(pathOrBuffer);
|
|
61
|
+
}
|
|
62
|
+
return new VisioDocument(pkg);
|
|
63
|
+
}
|
|
64
|
+
async addPage(name) {
|
|
65
|
+
const newId = await this.pageManager.createPage(name);
|
|
66
|
+
this._pageCache = null;
|
|
67
|
+
const pageStub = {
|
|
68
|
+
ID: newId,
|
|
69
|
+
Name: name,
|
|
70
|
+
Shapes: [],
|
|
71
|
+
Connects: []
|
|
72
|
+
};
|
|
73
|
+
return new Page_1.Page(pageStub, this.pkg, this.mediaManager);
|
|
74
|
+
}
|
|
75
|
+
get pages() {
|
|
76
|
+
if (!this._pageCache) {
|
|
77
|
+
const internalPages = this.pageManager.load();
|
|
78
|
+
this._pageCache = internalPages.map(p => {
|
|
79
|
+
// Adapter for VisioPage interface
|
|
80
|
+
const pageStub = {
|
|
81
|
+
ID: p.id.toString(),
|
|
82
|
+
Name: p.name,
|
|
83
|
+
Shapes: [],
|
|
84
|
+
Connects: [],
|
|
85
|
+
isBackground: p.isBackground,
|
|
86
|
+
backPageId: p.backPageId
|
|
87
|
+
};
|
|
88
|
+
return new Page_1.Page(pageStub, this.pkg, this.mediaManager);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return this._pageCache;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Add a background page to the document
|
|
95
|
+
*/
|
|
96
|
+
async addBackgroundPage(name) {
|
|
97
|
+
const newId = await this.pageManager.createBackgroundPage(name);
|
|
98
|
+
this._pageCache = null;
|
|
99
|
+
const pageStub = {
|
|
100
|
+
ID: newId,
|
|
101
|
+
Name: name,
|
|
102
|
+
Shapes: [],
|
|
103
|
+
Connects: [],
|
|
104
|
+
isBackground: true
|
|
105
|
+
};
|
|
106
|
+
return new Page_1.Page(pageStub, this.pkg, this.mediaManager);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Set a background page for a foreground page
|
|
110
|
+
*/
|
|
111
|
+
async setBackgroundPage(foregroundPage, backgroundPage) {
|
|
112
|
+
await this.pageManager.setBackgroundPage(foregroundPage.id, backgroundPage.id);
|
|
113
|
+
this._pageCache = null;
|
|
114
|
+
}
|
|
115
|
+
async save(filename) {
|
|
116
|
+
return this.pkg.save(filename);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.VisioDocument = VisioDocument;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class VisioPackage {
|
|
2
|
+
private zip;
|
|
3
|
+
private _files;
|
|
4
|
+
get filesMap(): Map<string, string | Buffer>;
|
|
5
|
+
static create(): Promise<VisioPackage>;
|
|
6
|
+
load(buffer: Buffer | ArrayBuffer | Uint8Array): Promise<void>;
|
|
7
|
+
updateFile(path: string, content: string | Buffer): void;
|
|
8
|
+
save(filename?: string): Promise<Buffer>;
|
|
9
|
+
getFileText(path: string): string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.VisioPackage = void 0;
|
|
40
|
+
const jszip_1 = __importDefault(require("jszip"));
|
|
41
|
+
const T = __importStar(require("./templates/MinimalVsdx"));
|
|
42
|
+
const MediaConstants_1 = require("./core/MediaConstants");
|
|
43
|
+
class VisioPackage {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.zip = null;
|
|
46
|
+
this._files = new Map();
|
|
47
|
+
}
|
|
48
|
+
get filesMap() {
|
|
49
|
+
return this._files;
|
|
50
|
+
}
|
|
51
|
+
static async create() {
|
|
52
|
+
const pkg = new VisioPackage();
|
|
53
|
+
pkg.zip = new jszip_1.default();
|
|
54
|
+
// Populate minimal structure
|
|
55
|
+
pkg.updateFile('[Content_Types].xml', T.CONTENT_TYPES_XML);
|
|
56
|
+
pkg.updateFile('_rels/.rels', T.RELS_XML);
|
|
57
|
+
pkg.updateFile('visio/document.xml', T.DOCUMENT_XML);
|
|
58
|
+
pkg.updateFile('visio/_rels/document.xml.rels', T.DOCUMENT_RELS_XML);
|
|
59
|
+
pkg.updateFile('visio/pages/pages.xml', T.PAGES_XML);
|
|
60
|
+
pkg.updateFile('visio/pages/_rels/pages.xml.rels', T.PAGES_RELS_XML);
|
|
61
|
+
pkg.updateFile('visio/pages/page1.xml', T.PAGE1_XML);
|
|
62
|
+
pkg.updateFile('visio/windows.xml', T.WINDOWS_XML);
|
|
63
|
+
pkg.updateFile('docProps/core.xml', T.CORE_XML);
|
|
64
|
+
pkg.updateFile('docProps/app.xml', T.APP_XML);
|
|
65
|
+
return pkg;
|
|
66
|
+
}
|
|
67
|
+
async load(buffer) {
|
|
68
|
+
this._files.clear();
|
|
69
|
+
this.zip = await jszip_1.default.loadAsync(buffer);
|
|
70
|
+
const promises = [];
|
|
71
|
+
this.zip.forEach((relativePath, file) => {
|
|
72
|
+
if (!file.dir) {
|
|
73
|
+
const ext = relativePath.split('.').pop() || '';
|
|
74
|
+
const isBinary = (0, MediaConstants_1.isBinaryExtension)(ext);
|
|
75
|
+
const type = isBinary ? 'nodebuffer' : 'string';
|
|
76
|
+
promises.push(file.async(type).then(content => {
|
|
77
|
+
this._files.set(relativePath, content);
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
await Promise.all(promises);
|
|
82
|
+
}
|
|
83
|
+
updateFile(path, content) {
|
|
84
|
+
if (!this.zip) {
|
|
85
|
+
throw new Error("Package not loaded");
|
|
86
|
+
}
|
|
87
|
+
this._files.set(path, content);
|
|
88
|
+
this.zip.file(path, content);
|
|
89
|
+
}
|
|
90
|
+
async save(filename) {
|
|
91
|
+
if (!this.zip) {
|
|
92
|
+
throw new Error("Package not loaded");
|
|
93
|
+
}
|
|
94
|
+
const buffer = await this.zip.generateAsync({ type: 'nodebuffer' });
|
|
95
|
+
if (filename) {
|
|
96
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
|
|
97
|
+
await fs.writeFile(filename, buffer);
|
|
98
|
+
}
|
|
99
|
+
return buffer;
|
|
100
|
+
}
|
|
101
|
+
getFileText(path) {
|
|
102
|
+
const content = this._files.get(path);
|
|
103
|
+
if (content === undefined) {
|
|
104
|
+
throw new Error(`File not found: ${path}`);
|
|
105
|
+
}
|
|
106
|
+
if (Buffer.isBuffer(content)) {
|
|
107
|
+
throw new Error(`File is binary: ${path}`);
|
|
108
|
+
}
|
|
109
|
+
return content;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.VisioPackage = VisioPackage;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { VisioPackage } from '../VisioPackage';
|
|
2
|
+
export interface Master {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
nameU: string;
|
|
6
|
+
type: string;
|
|
7
|
+
xmlPath: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class MasterManager {
|
|
10
|
+
private pkg;
|
|
11
|
+
private parser;
|
|
12
|
+
private masters;
|
|
13
|
+
constructor(pkg: VisioPackage);
|
|
14
|
+
load(): Master[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MasterManager = void 0;
|
|
4
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
5
|
+
class MasterManager {
|
|
6
|
+
constructor(pkg) {
|
|
7
|
+
this.pkg = pkg;
|
|
8
|
+
this.masters = [];
|
|
9
|
+
this.parser = new fast_xml_parser_1.XMLParser({
|
|
10
|
+
ignoreAttributes: false,
|
|
11
|
+
attributeNamePrefix: "@_"
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
load() {
|
|
15
|
+
const path = 'visio/masters/masters.xml';
|
|
16
|
+
let content;
|
|
17
|
+
try {
|
|
18
|
+
content = this.pkg.getFileText(path);
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
// It's possible the file doesn't exist if no masters are used
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
const parsed = this.parser.parse(content);
|
|
25
|
+
let masterNodes = parsed.Masters ? parsed.Masters.Master : [];
|
|
26
|
+
if (!Array.isArray(masterNodes)) {
|
|
27
|
+
masterNodes = [masterNodes];
|
|
28
|
+
}
|
|
29
|
+
this.masters = masterNodes.map((node) => ({
|
|
30
|
+
id: node['@_ID'],
|
|
31
|
+
name: node['@_Name'],
|
|
32
|
+
nameU: node['@_NameU'],
|
|
33
|
+
type: node['@_Type'],
|
|
34
|
+
// Implicit path convention in Visio typically follows patterns,
|
|
35
|
+
// but precise mapping usually requires checking relationships (.rels).
|
|
36
|
+
// For Phase 1, we'll assume standard naming or just store what we have.
|
|
37
|
+
// Relationships are handled in Phase 3.
|
|
38
|
+
xmlPath: ''
|
|
39
|
+
}));
|
|
40
|
+
return this.masters;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.MasterManager = MasterManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUPPORTED_IMAGE_EXTENSIONS = exports.MIME_TYPES = void 0;
|
|
4
|
+
exports.isBinaryExtension = isBinaryExtension;
|
|
5
|
+
exports.MIME_TYPES = {
|
|
6
|
+
'png': 'image/png',
|
|
7
|
+
'jpg': 'image/jpeg',
|
|
8
|
+
'jpeg': 'image/jpeg',
|
|
9
|
+
'gif': 'image/gif',
|
|
10
|
+
'bmp': 'image/bmp',
|
|
11
|
+
'tiff': 'image/tiff'
|
|
12
|
+
};
|
|
13
|
+
exports.SUPPORTED_IMAGE_EXTENSIONS = Object.keys(exports.MIME_TYPES);
|
|
14
|
+
function isBinaryExtension(ext) {
|
|
15
|
+
return exports.SUPPORTED_IMAGE_EXTENSIONS.includes(ext.toLowerCase());
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VisioPackage } from '../VisioPackage';
|
|
2
|
+
export declare class MediaManager {
|
|
3
|
+
private pkg;
|
|
4
|
+
private parser;
|
|
5
|
+
private builder;
|
|
6
|
+
private deduplicationMap;
|
|
7
|
+
private indexed;
|
|
8
|
+
constructor(pkg: VisioPackage);
|
|
9
|
+
private ensureIndex;
|
|
10
|
+
private getContentType;
|
|
11
|
+
addMedia(name: string, data: Buffer): string;
|
|
12
|
+
private ensureContentType;
|
|
13
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MediaManager = void 0;
|
|
4
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
5
|
+
const MediaConstants_1 = require("./MediaConstants");
|
|
6
|
+
class MediaManager {
|
|
7
|
+
constructor(pkg) {
|
|
8
|
+
this.pkg = pkg;
|
|
9
|
+
this.deduplicationMap = new Map(); // hash -> paths
|
|
10
|
+
this.indexed = false;
|
|
11
|
+
this.parser = new fast_xml_parser_1.XMLParser({
|
|
12
|
+
ignoreAttributes: false,
|
|
13
|
+
attributeNamePrefix: "@_"
|
|
14
|
+
});
|
|
15
|
+
this.builder = new fast_xml_parser_1.XMLBuilder({
|
|
16
|
+
ignoreAttributes: false,
|
|
17
|
+
attributeNamePrefix: "@_",
|
|
18
|
+
format: true
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
ensureIndex() {
|
|
22
|
+
if (this.indexed)
|
|
23
|
+
return;
|
|
24
|
+
const crypto = require('crypto');
|
|
25
|
+
for (const [path, content] of this.pkg.filesMap.entries()) {
|
|
26
|
+
if (path.startsWith('visio/media/') && Buffer.isBuffer(content)) {
|
|
27
|
+
const hash = crypto.createHash('sha1').update(content).digest('hex');
|
|
28
|
+
// Store relative path suitable for relationships
|
|
29
|
+
const filename = path.split('/').pop();
|
|
30
|
+
if (filename) {
|
|
31
|
+
this.deduplicationMap.set(hash, `../media/${filename}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
this.indexed = true;
|
|
36
|
+
}
|
|
37
|
+
getContentType(extension) {
|
|
38
|
+
return MediaConstants_1.MIME_TYPES[extension.toLowerCase()] || 'application/octet-stream';
|
|
39
|
+
}
|
|
40
|
+
addMedia(name, data) {
|
|
41
|
+
this.ensureIndex();
|
|
42
|
+
const crypto = require('crypto');
|
|
43
|
+
const hash = crypto.createHash('sha1').update(data).digest('hex');
|
|
44
|
+
if (this.deduplicationMap.has(hash)) {
|
|
45
|
+
return this.deduplicationMap.get(hash);
|
|
46
|
+
}
|
|
47
|
+
const extension = name.split('.').pop() || '';
|
|
48
|
+
// If name already exists, we might need a unique name.
|
|
49
|
+
// Note: Visio doesn't strictly require unique filenames in the media folder if we manage rels,
|
|
50
|
+
// but it's safer to avoid collisions.
|
|
51
|
+
// Use hash in filename to ensure uniqueness and automatic deduplication naming
|
|
52
|
+
const uniqueFileName = `${name.replace(`.${extension}`, '')}_${hash.substring(0, 8)}.${extension}`;
|
|
53
|
+
const mediaPath = `visio/media/${uniqueFileName}`;
|
|
54
|
+
const relPath = `../media/${uniqueFileName}`;
|
|
55
|
+
this.pkg.updateFile(mediaPath, data);
|
|
56
|
+
if (extension) {
|
|
57
|
+
this.ensureContentType(extension);
|
|
58
|
+
}
|
|
59
|
+
this.deduplicationMap.set(hash, relPath);
|
|
60
|
+
return relPath;
|
|
61
|
+
}
|
|
62
|
+
ensureContentType(extension) {
|
|
63
|
+
const ctPath = '[Content_Types].xml';
|
|
64
|
+
const content = this.pkg.getFileText(ctPath);
|
|
65
|
+
const parsed = this.parser.parse(content);
|
|
66
|
+
// Ensure structure
|
|
67
|
+
if (!parsed.Types)
|
|
68
|
+
parsed.Types = {};
|
|
69
|
+
if (!parsed.Types.Default)
|
|
70
|
+
parsed.Types.Default = [];
|
|
71
|
+
// Ensure array
|
|
72
|
+
if (!Array.isArray(parsed.Types.Default)) {
|
|
73
|
+
parsed.Types.Default = [parsed.Types.Default];
|
|
74
|
+
}
|
|
75
|
+
const defaults = parsed.Types.Default;
|
|
76
|
+
const exists = defaults.some((d) => d['@_Extension']?.toLowerCase() === extension);
|
|
77
|
+
if (!exists) {
|
|
78
|
+
defaults.push({
|
|
79
|
+
'@_Extension': extension,
|
|
80
|
+
'@_ContentType': this.getContentType(extension)
|
|
81
|
+
});
|
|
82
|
+
// Array reference is already mutating object
|
|
83
|
+
const newXml = this.builder.build(parsed);
|
|
84
|
+
this.pkg.updateFile(ctPath, newXml);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.MediaManager = MediaManager;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { VisioPackage } from '../VisioPackage';
|
|
2
|
+
export interface PageEntry {
|
|
3
|
+
id: number;
|
|
4
|
+
name: string;
|
|
5
|
+
relId: string;
|
|
6
|
+
xmlPath: string;
|
|
7
|
+
isBackground: boolean;
|
|
8
|
+
backPageId?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class PageManager {
|
|
11
|
+
private pkg;
|
|
12
|
+
private parser;
|
|
13
|
+
private builder;
|
|
14
|
+
private relsManager;
|
|
15
|
+
private pages;
|
|
16
|
+
private loaded;
|
|
17
|
+
constructor(pkg: VisioPackage);
|
|
18
|
+
load(force?: boolean): PageEntry[];
|
|
19
|
+
createPage(name: string): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Create a background page
|
|
22
|
+
*/
|
|
23
|
+
createBackgroundPage(name: string): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Set a background page for a foreground page
|
|
26
|
+
*/
|
|
27
|
+
setBackgroundPage(foregroundPageId: string, backgroundPageId: string): Promise<void>;
|
|
28
|
+
}
|