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,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContainerBuilder = void 0;
|
|
4
|
+
const ShapeBuilder_1 = require("./ShapeBuilder");
|
|
5
|
+
class ContainerBuilder {
|
|
6
|
+
static createContainerShape(id, props) {
|
|
7
|
+
// Reuse basic shape creation (transform, text, etc)
|
|
8
|
+
const shape = ShapeBuilder_1.ShapeBuilder.createStandardShape(id, props);
|
|
9
|
+
// Styling Override for "Classic Container":
|
|
10
|
+
// Usually containers have a Header implementation or specific Geometry.
|
|
11
|
+
// For Phase 1, we will stick to a basic Rectangle with the Metadata.
|
|
12
|
+
// If the user wants "classic" look, we might need 2 geometries (Header + Body).
|
|
13
|
+
// 1. Inject Container Metadata (User Cells)
|
|
14
|
+
this.makeContainer(shape);
|
|
15
|
+
// 2. Adjust styling if necessary
|
|
16
|
+
// Containers often have 'NoFill' for the body so you can see behind,
|
|
17
|
+
// or they have a Group structure.
|
|
18
|
+
// For a simple single-shape container, we rely on the Geometry.
|
|
19
|
+
return shape;
|
|
20
|
+
}
|
|
21
|
+
static makeContainer(shape) {
|
|
22
|
+
// Ensure Section array
|
|
23
|
+
if (!shape.Section)
|
|
24
|
+
shape.Section = [];
|
|
25
|
+
if (!Array.isArray(shape.Section))
|
|
26
|
+
shape.Section = [shape.Section];
|
|
27
|
+
// 1. User Section (Metadata)
|
|
28
|
+
let userSection = shape.Section.find((s) => s['@_N'] === 'User');
|
|
29
|
+
if (!userSection) {
|
|
30
|
+
userSection = { '@_N': 'User', Row: [] };
|
|
31
|
+
shape.Section.push(userSection);
|
|
32
|
+
}
|
|
33
|
+
// Ensure Row is array (Critical for XML parser edge cases)
|
|
34
|
+
if (!userSection.Row)
|
|
35
|
+
userSection.Row = [];
|
|
36
|
+
if (!Array.isArray(userSection.Row))
|
|
37
|
+
userSection.Row = [userSection.Row];
|
|
38
|
+
// Helper to add/update user row
|
|
39
|
+
const addUserRow = (name, value) => {
|
|
40
|
+
const rowIdx = userSection.Row.findIndex((r) => r['@_N'] === name);
|
|
41
|
+
const newRow = {
|
|
42
|
+
'@_N': name,
|
|
43
|
+
Cell: [{ '@_N': 'Value', '@_V': value }]
|
|
44
|
+
};
|
|
45
|
+
if (rowIdx >= 0) {
|
|
46
|
+
userSection.Row[rowIdx] = newRow;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
userSection.Row.push(newRow);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
// Critical Metadata
|
|
53
|
+
addUserRow('msvStructureType', '"Container"');
|
|
54
|
+
addUserRow('msvSDContainerMargin', '10 mm');
|
|
55
|
+
// 2. Adjust Text Position (Simulate Header)
|
|
56
|
+
// Find or create TextXform
|
|
57
|
+
let textXform = shape.Section.find((s) => s['@_N'] === 'TextXform');
|
|
58
|
+
if (!textXform) {
|
|
59
|
+
textXform = { '@_N': 'TextXform', Cell: [] };
|
|
60
|
+
shape.Section.push(textXform);
|
|
61
|
+
}
|
|
62
|
+
// Ensure Cell is array
|
|
63
|
+
if (!textXform.Cell)
|
|
64
|
+
textXform.Cell = [];
|
|
65
|
+
if (!Array.isArray(textXform.Cell))
|
|
66
|
+
textXform.Cell = [textXform.Cell];
|
|
67
|
+
const upsertCell = (name, val, unit) => {
|
|
68
|
+
const idx = textXform.Cell.findIndex((c) => c['@_N'] === name);
|
|
69
|
+
const cell = { '@_N': name, '@_V': val, '@_U': unit };
|
|
70
|
+
if (idx >= 0)
|
|
71
|
+
textXform.Cell[idx] = cell;
|
|
72
|
+
else
|
|
73
|
+
textXform.Cell.push(cell);
|
|
74
|
+
};
|
|
75
|
+
// Move text to top of shape: TxtPinY = Height, TxtLocPinY = TxtHeight
|
|
76
|
+
// Removed redundant '*1' from formulas
|
|
77
|
+
upsertCell('TxtPinY', 'Height', 'DY');
|
|
78
|
+
upsertCell('TxtLocPinY', 'TxtHeight', 'DY');
|
|
79
|
+
}
|
|
80
|
+
static makeList(shape, direction = 'vertical') {
|
|
81
|
+
// 1. Convert basic container to List
|
|
82
|
+
this.makeContainer(shape);
|
|
83
|
+
// 2. User Section Override
|
|
84
|
+
let userSection = shape.Section.find((s) => s['@_N'] === 'User');
|
|
85
|
+
// Helper to add/update user row
|
|
86
|
+
const upsertUserRow = (name, value) => {
|
|
87
|
+
const rowIdx = userSection.Row.findIndex((r) => r['@_N'] === name);
|
|
88
|
+
const newRow = {
|
|
89
|
+
'@_N': name,
|
|
90
|
+
Cell: [{ '@_N': 'Value', '@_V': value }]
|
|
91
|
+
};
|
|
92
|
+
if (rowIdx >= 0)
|
|
93
|
+
userSection.Row[rowIdx] = newRow;
|
|
94
|
+
else
|
|
95
|
+
userSection.Row.push(newRow);
|
|
96
|
+
};
|
|
97
|
+
upsertUserRow('msvStructureType', '"List"'); // Override "Container"
|
|
98
|
+
upsertUserRow('msvSDListDirection', direction === 'vertical' ? '1' : '0'); // 1=Vert, 0=Horiz
|
|
99
|
+
upsertUserRow('msvSDListSpacing', '0.125'); // Default spacing (can be param later)
|
|
100
|
+
upsertUserRow('msvSDListAlignment', '1'); // 1=Center
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.ContainerBuilder = ContainerBuilder;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ForeignShapeBuilder = void 0;
|
|
4
|
+
class ForeignShapeBuilder {
|
|
5
|
+
static createImageShapeObject(id, rId, props) {
|
|
6
|
+
return {
|
|
7
|
+
'@_ID': id,
|
|
8
|
+
'@_NameU': `Sheet.${id}`,
|
|
9
|
+
'@_Name': `Sheet.${id}`,
|
|
10
|
+
'@_Type': 'Foreign',
|
|
11
|
+
ForeignData: { '@_r:id': rId },
|
|
12
|
+
Cell: [
|
|
13
|
+
{ '@_N': 'PinX', '@_V': props.x.toString() },
|
|
14
|
+
{ '@_N': 'PinY', '@_V': props.y.toString() },
|
|
15
|
+
{ '@_N': 'Width', '@_V': props.width.toString() },
|
|
16
|
+
{ '@_N': 'Height', '@_V': props.height.toString() },
|
|
17
|
+
{ '@_N': 'LocPinX', '@_V': (props.width / 2).toString() },
|
|
18
|
+
{ '@_N': 'LocPinY', '@_V': (props.height / 2).toString() }
|
|
19
|
+
],
|
|
20
|
+
Section: [
|
|
21
|
+
// Foreign shapes typically have no border (LinePattern=0)
|
|
22
|
+
{
|
|
23
|
+
'@_N': 'Line',
|
|
24
|
+
Cell: [
|
|
25
|
+
{ '@_N': 'LinePattern', '@_V': '0' }, // 0 = Null/No Line
|
|
26
|
+
{ '@_N': 'LineColor', '@_V': '#000000' },
|
|
27
|
+
{ '@_N': 'LineWeight', '@_V': '0' }
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
// Geometry is required for selection bounds
|
|
31
|
+
{
|
|
32
|
+
'@_N': 'Geometry',
|
|
33
|
+
'@_IX': '0',
|
|
34
|
+
Cell: [{ '@_N': 'NoFill', '@_V': '1' }], // Images usually don't have a fill behind them
|
|
35
|
+
Row: [
|
|
36
|
+
{ '@_T': 'MoveTo', '@_IX': '1', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': '0' }] },
|
|
37
|
+
{ '@_T': 'LineTo', '@_IX': '2', Cell: [{ '@_N': 'X', '@_V': props.width.toString() }, { '@_N': 'Y', '@_V': '0' }] },
|
|
38
|
+
{ '@_T': 'LineTo', '@_IX': '3', Cell: [{ '@_N': 'X', '@_V': props.width.toString() }, { '@_N': 'Y', '@_V': props.height.toString() }] },
|
|
39
|
+
{ '@_T': 'LineTo', '@_IX': '4', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': props.height.toString() }] },
|
|
40
|
+
{ '@_T': 'LineTo', '@_IX': '5', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': '0' }] }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.ForeignShapeBuilder = ForeignShapeBuilder;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ShapeBuilder = void 0;
|
|
4
|
+
const StyleHelpers_1 = require("../utils/StyleHelpers");
|
|
5
|
+
class ShapeBuilder {
|
|
6
|
+
static createStandardShape(id, props) {
|
|
7
|
+
// Validate dimensions
|
|
8
|
+
if (props.width <= 0 || props.height <= 0) {
|
|
9
|
+
throw new Error('Shape dimensions must be positive numbers');
|
|
10
|
+
}
|
|
11
|
+
const shape = {
|
|
12
|
+
'@_ID': id,
|
|
13
|
+
'@_NameU': `Sheet.${id}`,
|
|
14
|
+
'@_Name': `Sheet.${id}`,
|
|
15
|
+
'@_Type': props.type || 'Shape',
|
|
16
|
+
Cell: [
|
|
17
|
+
{ '@_N': 'PinX', '@_V': props.x.toString() },
|
|
18
|
+
{ '@_N': 'PinY', '@_V': props.y.toString() },
|
|
19
|
+
{ '@_N': 'Width', '@_V': props.width.toString() },
|
|
20
|
+
{ '@_N': 'Height', '@_V': props.height.toString() },
|
|
21
|
+
{ '@_N': 'LocPinX', '@_V': (props.width / 2).toString() },
|
|
22
|
+
{ '@_N': 'LocPinY', '@_V': (props.height / 2).toString() }
|
|
23
|
+
],
|
|
24
|
+
Section: []
|
|
25
|
+
// Text added at end by caller or we can do it here if props.text is final
|
|
26
|
+
};
|
|
27
|
+
if (props.masterId) {
|
|
28
|
+
shape['@_Master'] = props.masterId;
|
|
29
|
+
}
|
|
30
|
+
// Add Styles
|
|
31
|
+
if (props.fillColor) {
|
|
32
|
+
shape.Section.push((0, StyleHelpers_1.createFillSection)(props.fillColor));
|
|
33
|
+
// Standard Line for fillable shapes
|
|
34
|
+
shape.Section.push((0, StyleHelpers_1.createLineSection)({
|
|
35
|
+
color: props.lineColor || '#000000',
|
|
36
|
+
weight: '0.01'
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
if (props.fontColor || props.bold) {
|
|
40
|
+
shape.Section.push((0, StyleHelpers_1.createCharacterSection)({
|
|
41
|
+
bold: props.bold,
|
|
42
|
+
color: props.fontColor
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
// Add Geometry
|
|
46
|
+
// Only if NOT a Group AND NOT a Master Instance
|
|
47
|
+
if (props.type !== 'Group' && !props.masterId) {
|
|
48
|
+
shape.Section.push({
|
|
49
|
+
'@_N': 'Geometry',
|
|
50
|
+
'@_IX': '0',
|
|
51
|
+
Cell: [{ '@_N': 'NoFill', '@_V': props.fillColor ? '0' : '1' }],
|
|
52
|
+
Row: [
|
|
53
|
+
{ '@_T': 'MoveTo', '@_IX': '1', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': '0' }] },
|
|
54
|
+
{ '@_T': 'LineTo', '@_IX': '2', Cell: [{ '@_N': 'X', '@_V': props.width.toString() }, { '@_N': 'Y', '@_V': '0' }] },
|
|
55
|
+
{ '@_T': 'LineTo', '@_IX': '3', Cell: [{ '@_N': 'X', '@_V': props.width.toString() }, { '@_N': 'Y', '@_V': props.height.toString() }] },
|
|
56
|
+
{ '@_T': 'LineTo', '@_IX': '4', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': props.height.toString() }] },
|
|
57
|
+
{ '@_T': 'LineTo', '@_IX': '5', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': '0' }] }
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// Handle Text if provided
|
|
62
|
+
if (props.text !== undefined && props.text !== null) {
|
|
63
|
+
shape.Text = { '#text': props.text };
|
|
64
|
+
}
|
|
65
|
+
return shape;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.ShapeBuilder = ShapeBuilder;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const CONTENT_TYPES_XML: string;
|
|
2
|
+
export declare const RELS_XML: string;
|
|
3
|
+
export declare const DOCUMENT_XML: string;
|
|
4
|
+
export declare const DOCUMENT_RELS_XML: string;
|
|
5
|
+
export declare const PAGES_XML: string;
|
|
6
|
+
export declare const PAGES_RELS_XML: string;
|
|
7
|
+
export declare const PAGE1_XML: string;
|
|
8
|
+
export declare const WINDOWS_XML: string;
|
|
9
|
+
export declare const CORE_XML: string;
|
|
10
|
+
export declare const APP_XML: string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APP_XML = exports.CORE_XML = exports.WINDOWS_XML = exports.PAGE1_XML = exports.PAGES_RELS_XML = exports.PAGES_XML = exports.DOCUMENT_RELS_XML = exports.DOCUMENT_XML = exports.RELS_XML = exports.CONTENT_TYPES_XML = void 0;
|
|
4
|
+
const VisioConstants_1 = require("../core/VisioConstants");
|
|
5
|
+
exports.CONTENT_TYPES_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
6
|
+
<Types xmlns="${VisioConstants_1.XML_NAMESPACES.CONTENT_TYPES}">
|
|
7
|
+
<Default Extension="rels" ContentType="${VisioConstants_1.CONTENT_TYPES.XML_RELATIONSHIPS}"/>
|
|
8
|
+
<Default Extension="xml" ContentType="${VisioConstants_1.CONTENT_TYPES.XML}"/>
|
|
9
|
+
<Override PartName="/visio/document.xml" ContentType="${VisioConstants_1.CONTENT_TYPES.VISIO_DRAWING}"/>
|
|
10
|
+
<Override PartName="/visio/pages/pages.xml" ContentType="${VisioConstants_1.CONTENT_TYPES.VISIO_PAGES}"/>
|
|
11
|
+
<Override PartName="/visio/pages/page1.xml" ContentType="${VisioConstants_1.CONTENT_TYPES.VISIO_PAGE}"/>
|
|
12
|
+
<Override PartName="/visio/windows.xml" ContentType="${VisioConstants_1.CONTENT_TYPES.VISIO_WINDOWS}"/>
|
|
13
|
+
<Override PartName="/docProps/core.xml" ContentType="${VisioConstants_1.CONTENT_TYPES.CORE_PROPERTIES}"/>
|
|
14
|
+
<Override PartName="/docProps/app.xml" ContentType="${VisioConstants_1.CONTENT_TYPES.EXTENDED_PROPERTIES}"/>
|
|
15
|
+
</Types>`;
|
|
16
|
+
exports.RELS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
17
|
+
<Relationships xmlns="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS}">
|
|
18
|
+
<Relationship Id="rId1" Type="${VisioConstants_1.RELATIONSHIP_TYPES.DOCUMENT}" Target="visio/document.xml"/>
|
|
19
|
+
<Relationship Id="rId2" Type="${VisioConstants_1.RELATIONSHIP_TYPES.CORE_PROPERTIES}" Target="docProps/core.xml"/>
|
|
20
|
+
<Relationship Id="rId3" Type="${VisioConstants_1.RELATIONSHIP_TYPES.EXTENDED_PROPERTIES}" Target="docProps/app.xml"/>
|
|
21
|
+
</Relationships>`;
|
|
22
|
+
exports.DOCUMENT_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
23
|
+
<VisioDocument xmlns="${VisioConstants_1.XML_NAMESPACES.VISIO_MAIN}" xmlns:r="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS_OFFICE}" xml:space="preserve" Language="en-US">
|
|
24
|
+
<DocumentSettings TopPage="0" DefaultTextStyle="0" DefaultLineStyle="0" DefaultFillStyle="0" DefaultGuideStyle="0"/>
|
|
25
|
+
<Colors>
|
|
26
|
+
<ColorEntry IX="0" RGB="#000000"/>
|
|
27
|
+
<ColorEntry IX="1" RGB="#FFFFFF"/>
|
|
28
|
+
</Colors>
|
|
29
|
+
<FaceNames/>
|
|
30
|
+
<StyleSheets/>
|
|
31
|
+
</VisioDocument>`;
|
|
32
|
+
exports.DOCUMENT_RELS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
33
|
+
<Relationships xmlns="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS}">
|
|
34
|
+
<Relationship Id="rId1" Type="${VisioConstants_1.RELATIONSHIP_TYPES.PAGES}" Target="pages/pages.xml"/>
|
|
35
|
+
<Relationship Id="rId2" Type="${VisioConstants_1.RELATIONSHIP_TYPES.WINDOWS}" Target="windows.xml"/>
|
|
36
|
+
</Relationships>`;
|
|
37
|
+
exports.PAGES_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
38
|
+
<Pages xmlns="${VisioConstants_1.XML_NAMESPACES.VISIO_MAIN}" xmlns:r="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS_OFFICE}" xml:space="preserve">
|
|
39
|
+
<Page ID="1" Name="Page-1" NameU="Page-1" ViewScale="1" ViewCenterX="4.133858267716535" ViewCenterY="5.846456692913386">
|
|
40
|
+
<Rel r:id="rId1"/>
|
|
41
|
+
</Page>
|
|
42
|
+
</Pages>`;
|
|
43
|
+
exports.PAGES_RELS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
44
|
+
<Relationships xmlns="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS}">
|
|
45
|
+
<Relationship Id="rId1" Type="${VisioConstants_1.RELATIONSHIP_TYPES.PAGE}" Target="page1.xml"/>
|
|
46
|
+
</Relationships>`;
|
|
47
|
+
exports.PAGE1_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
48
|
+
<PageContents xmlns="${VisioConstants_1.XML_NAMESPACES.VISIO_MAIN}" xmlns:r="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS_OFFICE}" xml:space="preserve">
|
|
49
|
+
<Shapes/>
|
|
50
|
+
</PageContents>`;
|
|
51
|
+
exports.WINDOWS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
52
|
+
<Windows xmlns="${VisioConstants_1.XML_NAMESPACES.VISIO_MAIN}" xmlns:r="${VisioConstants_1.XML_NAMESPACES.RELATIONSHIPS_OFFICE}" xml:space="preserve">
|
|
53
|
+
<Window ID="0" WindowType="Drawing" WindowState="1073741824" WindowLeft="0" WindowTop="0" WindowWidth="1024" WindowHeight="768" Container="0" ContainerType="Page" Sheet="0"/>
|
|
54
|
+
</Windows>`;
|
|
55
|
+
exports.CORE_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
56
|
+
<cp:coreProperties xmlns:cp="${VisioConstants_1.XML_NAMESPACES.CORE_PROPERTIES}" xmlns:dc="${VisioConstants_1.XML_NAMESPACES.DC_ELEMENTS}" xmlns:dcterms="${VisioConstants_1.XML_NAMESPACES.DC_TERMS}" xmlns:dcmitype="${VisioConstants_1.XML_NAMESPACES.DC_DCMITYPE}" xmlns:xsi="${VisioConstants_1.XML_NAMESPACES.XSI}">
|
|
57
|
+
<dc:title>Drawing1</dc:title>
|
|
58
|
+
<dc:creator>ts-visio</dc:creator>
|
|
59
|
+
<cp:lastModifiedBy>ts-visio</cp:lastModifiedBy>
|
|
60
|
+
<cp:revision>1</cp:revision>
|
|
61
|
+
</cp:coreProperties>`;
|
|
62
|
+
exports.APP_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
63
|
+
<Properties xmlns="${VisioConstants_1.XML_NAMESPACES.EXTENDED_PROPERTIES}" xmlns:vt="${VisioConstants_1.XML_NAMESPACES.DOC_PROPS_VTYPES}">
|
|
64
|
+
<Template>Basic</Template>
|
|
65
|
+
<Application>ts-visio</Application>
|
|
66
|
+
</Properties>`;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface VisioCell {
|
|
2
|
+
N: string;
|
|
3
|
+
V: string;
|
|
4
|
+
U?: string;
|
|
5
|
+
F?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface VisioRow {
|
|
8
|
+
T?: string;
|
|
9
|
+
N?: string;
|
|
10
|
+
IX?: number;
|
|
11
|
+
Cells: {
|
|
12
|
+
[name: string]: VisioCell;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface VisioSection {
|
|
16
|
+
N: string;
|
|
17
|
+
Rows: VisioRow[];
|
|
18
|
+
Cells?: {
|
|
19
|
+
[name: string]: VisioCell;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface VisioShape {
|
|
23
|
+
ID: string;
|
|
24
|
+
Name: string;
|
|
25
|
+
NameU?: string;
|
|
26
|
+
Type: string;
|
|
27
|
+
Master?: string;
|
|
28
|
+
Text?: string;
|
|
29
|
+
Cells: {
|
|
30
|
+
[name: string]: VisioCell;
|
|
31
|
+
};
|
|
32
|
+
Sections: {
|
|
33
|
+
[name: string]: VisioSection;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface VisioConnect {
|
|
37
|
+
FromSheet: string;
|
|
38
|
+
FromCell: string;
|
|
39
|
+
FromPart?: number;
|
|
40
|
+
ToSheet: string;
|
|
41
|
+
ToCell: string;
|
|
42
|
+
ToPart?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface VisioPage {
|
|
45
|
+
ID: string;
|
|
46
|
+
Name: string;
|
|
47
|
+
NameU?: string;
|
|
48
|
+
Shapes: VisioShape[];
|
|
49
|
+
Connects: VisioConnect[];
|
|
50
|
+
isBackground?: boolean;
|
|
51
|
+
backPageId?: string;
|
|
52
|
+
PageSheet?: {
|
|
53
|
+
Cells: {
|
|
54
|
+
[name: string]: VisioCell;
|
|
55
|
+
};
|
|
56
|
+
Sections: {
|
|
57
|
+
[name: string]: VisioSection;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export declare enum VisioPropType {
|
|
62
|
+
String = 0,
|
|
63
|
+
FixedList = 1,
|
|
64
|
+
Number = 2,
|
|
65
|
+
Boolean = 3,
|
|
66
|
+
VariableList = 4,
|
|
67
|
+
Date = 5,
|
|
68
|
+
Duration = 6,
|
|
69
|
+
Currency = 7
|
|
70
|
+
}
|
|
71
|
+
export interface NewShapeProps {
|
|
72
|
+
text: string;
|
|
73
|
+
x: number;
|
|
74
|
+
y: number;
|
|
75
|
+
width: number;
|
|
76
|
+
height: number;
|
|
77
|
+
id?: string;
|
|
78
|
+
fillColor?: string;
|
|
79
|
+
fontColor?: string;
|
|
80
|
+
bold?: boolean;
|
|
81
|
+
type?: string;
|
|
82
|
+
masterId?: string;
|
|
83
|
+
imgRelId?: string;
|
|
84
|
+
lineColor?: string;
|
|
85
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VisioPropType = void 0;
|
|
4
|
+
var VisioPropType;
|
|
5
|
+
(function (VisioPropType) {
|
|
6
|
+
VisioPropType[VisioPropType["String"] = 0] = "String";
|
|
7
|
+
VisioPropType[VisioPropType["FixedList"] = 1] = "FixedList";
|
|
8
|
+
VisioPropType[VisioPropType["Number"] = 2] = "Number";
|
|
9
|
+
VisioPropType[VisioPropType["Boolean"] = 3] = "Boolean";
|
|
10
|
+
VisioPropType[VisioPropType["VariableList"] = 4] = "VariableList";
|
|
11
|
+
VisioPropType[VisioPropType["Date"] = 5] = "Date";
|
|
12
|
+
VisioPropType[VisioPropType["Duration"] = 6] = "Duration";
|
|
13
|
+
VisioPropType[VisioPropType["Currency"] = 7] = "Currency";
|
|
14
|
+
})(VisioPropType || (exports.VisioPropType = VisioPropType = {}));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createVisioShapeStub = createVisioShapeStub;
|
|
4
|
+
function createVisioShapeStub(props) {
|
|
5
|
+
return {
|
|
6
|
+
ID: props.ID,
|
|
7
|
+
Name: props.Name || `Sheet.${props.ID}`,
|
|
8
|
+
Type: 'Shape',
|
|
9
|
+
Text: props.Text,
|
|
10
|
+
Cells: Object.entries(props.Cells || {}).reduce((acc, [k, v]) => {
|
|
11
|
+
acc[k] = { N: k, V: v.toString() };
|
|
12
|
+
return acc;
|
|
13
|
+
}, {}),
|
|
14
|
+
Sections: {}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface VisioSection {
|
|
2
|
+
'@_N': string;
|
|
3
|
+
'@_IX'?: string;
|
|
4
|
+
Row?: any[];
|
|
5
|
+
Cell?: any[];
|
|
6
|
+
}
|
|
7
|
+
export declare function createFillSection(hexColor: string): VisioSection;
|
|
8
|
+
export declare const ArrowHeads: {
|
|
9
|
+
None: string;
|
|
10
|
+
Standard: string;
|
|
11
|
+
Open: string;
|
|
12
|
+
Stealth: string;
|
|
13
|
+
Diamond: string;
|
|
14
|
+
Oneway: string;
|
|
15
|
+
CrowsFoot: string;
|
|
16
|
+
One: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function createCharacterSection(props: {
|
|
19
|
+
bold?: boolean;
|
|
20
|
+
color?: string;
|
|
21
|
+
}): VisioSection;
|
|
22
|
+
export declare function createLineSection(props: {
|
|
23
|
+
color?: string;
|
|
24
|
+
pattern?: string;
|
|
25
|
+
weight?: string;
|
|
26
|
+
beginArrow?: string;
|
|
27
|
+
beginArrowSize?: string;
|
|
28
|
+
endArrow?: string;
|
|
29
|
+
endArrowSize?: string;
|
|
30
|
+
}): VisioSection;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArrowHeads = void 0;
|
|
4
|
+
exports.createFillSection = createFillSection;
|
|
5
|
+
exports.createCharacterSection = createCharacterSection;
|
|
6
|
+
exports.createLineSection = createLineSection;
|
|
7
|
+
const hexToRgb = (hex) => {
|
|
8
|
+
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
9
|
+
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
10
|
+
hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
|
|
11
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
12
|
+
return result ? `RGB(${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)})` : 'RGB(0,0,0)';
|
|
13
|
+
};
|
|
14
|
+
function createFillSection(hexColor) {
|
|
15
|
+
// Visio uses FillForegnd for the main background color.
|
|
16
|
+
// Ideally we should sanitize hexColor to be #RRGGBB.
|
|
17
|
+
const rgbFormula = hexToRgb(hexColor);
|
|
18
|
+
return {
|
|
19
|
+
'@_N': 'Fill',
|
|
20
|
+
Cell: [
|
|
21
|
+
{ '@_N': 'FillForegnd', '@_V': hexColor, '@_F': rgbFormula },
|
|
22
|
+
{ '@_N': 'FillBkgnd', '@_V': '#FFFFFF' }, // Default background pattern color usually white
|
|
23
|
+
{ '@_N': 'FillPattern', '@_V': '1' } // 1 = Solid fill
|
|
24
|
+
]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.ArrowHeads = {
|
|
28
|
+
None: '0',
|
|
29
|
+
Standard: '1',
|
|
30
|
+
Open: '2',
|
|
31
|
+
Stealth: '3',
|
|
32
|
+
Diamond: '4',
|
|
33
|
+
Oneway: '5',
|
|
34
|
+
CrowsFoot: '29', // Visio "Many"
|
|
35
|
+
One: '24', // Visio "One" (Dash) - Approximate, or '26'
|
|
36
|
+
// There are many variants, but 29 is the standard "Fork"
|
|
37
|
+
};
|
|
38
|
+
function createCharacterSection(props) {
|
|
39
|
+
// Visio Character Section
|
|
40
|
+
// N="Character"
|
|
41
|
+
// Row T="Character"
|
|
42
|
+
// Cell N="Color" V="#FF0000"
|
|
43
|
+
// Cell N="Style" V="1" (1=Bold, 2=Italic, 4=Underline) - Bitwise
|
|
44
|
+
// Visio booleans are often 0 or 1.
|
|
45
|
+
// Style=1 (Bold)
|
|
46
|
+
// Default Style is 0 (Normal)
|
|
47
|
+
let styleVal = 0;
|
|
48
|
+
if (props.bold) {
|
|
49
|
+
styleVal += 1; // Add Bold bit
|
|
50
|
+
}
|
|
51
|
+
// Default Color is usually 0 (Black) or specific hex
|
|
52
|
+
const colorVal = props.color || '#000000';
|
|
53
|
+
return {
|
|
54
|
+
'@_N': 'Character',
|
|
55
|
+
Row: [
|
|
56
|
+
{
|
|
57
|
+
'@_T': 'Character',
|
|
58
|
+
'@_IX': '0',
|
|
59
|
+
Cell: [
|
|
60
|
+
{ '@_N': 'Color', '@_V': colorVal, '@_F': hexToRgb(colorVal) },
|
|
61
|
+
{ '@_N': 'Style', '@_V': styleVal.toString() },
|
|
62
|
+
// Size, Font, etc could go here
|
|
63
|
+
{ '@_N': 'Font', '@_V': '1' } // Default font (Calibri usually)
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function createLineSection(props) {
|
|
70
|
+
const cells = [
|
|
71
|
+
{ '@_N': 'LineColor', '@_V': props.color || '#000000' },
|
|
72
|
+
{ '@_N': 'LinePattern', '@_V': props.pattern || '1' }, // 1 = Solid
|
|
73
|
+
{ '@_N': 'LineWeight', '@_V': props.weight || '0.01' } // ~0.72pt
|
|
74
|
+
];
|
|
75
|
+
// Add RGB Formula for custom colors
|
|
76
|
+
if (props.color) {
|
|
77
|
+
cells[0]['@_F'] = hexToRgb(props.color);
|
|
78
|
+
}
|
|
79
|
+
if (props.beginArrow) {
|
|
80
|
+
cells.push({ '@_N': 'BeginArrow', '@_V': props.beginArrow });
|
|
81
|
+
}
|
|
82
|
+
if (props.beginArrowSize) {
|
|
83
|
+
cells.push({ '@_N': 'BeginArrowSize', '@_V': props.beginArrowSize });
|
|
84
|
+
}
|
|
85
|
+
if (props.endArrow) {
|
|
86
|
+
cells.push({ '@_N': 'EndArrow', '@_V': props.endArrow });
|
|
87
|
+
}
|
|
88
|
+
if (props.endArrowSize) {
|
|
89
|
+
cells.push({ '@_N': 'EndArrowSize', '@_V': props.endArrowSize });
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
'@_N': 'Line',
|
|
93
|
+
Cell: cells
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { VisioCell, VisioSection } from '../types/VisioTypes';
|
|
2
|
+
export declare const asArray: <T>(obj: any) => T[];
|
|
3
|
+
export declare const parseCells: (container: any) => {
|
|
4
|
+
[name: string]: VisioCell;
|
|
5
|
+
};
|
|
6
|
+
export declare const parseSection: (sectionData: any) => VisioSection;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSection = exports.parseCells = exports.asArray = void 0;
|
|
4
|
+
const asArray = (obj) => {
|
|
5
|
+
if (!obj)
|
|
6
|
+
return [];
|
|
7
|
+
return Array.isArray(obj) ? obj : [obj];
|
|
8
|
+
};
|
|
9
|
+
exports.asArray = asArray;
|
|
10
|
+
const parseCells = (container) => {
|
|
11
|
+
const cells = {};
|
|
12
|
+
const cellData = (0, exports.asArray)(container.Cell);
|
|
13
|
+
for (const c of cellData) {
|
|
14
|
+
const cell = c;
|
|
15
|
+
if (cell['@_N']) {
|
|
16
|
+
cells[cell['@_N']] = {
|
|
17
|
+
N: cell['@_N'],
|
|
18
|
+
V: cell['@_V'],
|
|
19
|
+
U: cell['@_U'],
|
|
20
|
+
F: cell['@_F']
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return cells;
|
|
25
|
+
};
|
|
26
|
+
exports.parseCells = parseCells;
|
|
27
|
+
const parseSection = (sectionData) => {
|
|
28
|
+
const rows = [];
|
|
29
|
+
const rowData = (0, exports.asArray)(sectionData.Row);
|
|
30
|
+
for (const r of rowData) {
|
|
31
|
+
const row = r;
|
|
32
|
+
rows.push({
|
|
33
|
+
T: row['@_T'],
|
|
34
|
+
N: row['@_N'],
|
|
35
|
+
IX: row['@_IX'],
|
|
36
|
+
Cells: (0, exports.parseCells)(row)
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
N: sectionData['@_N'],
|
|
41
|
+
Rows: rows,
|
|
42
|
+
Cells: (0, exports.parseCells)(sectionData) // Attempt to parse direct cells
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
exports.parseSection = parseSection;
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ts-visio",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "vitest",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "Walt Zimmerman (me@waltzimmerman.com)",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"description": "A npm package for creating Visio files (vsdx) using TypeScript.",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"fast-xml-parser": "^5.3.3",
|
|
20
|
+
"jszip": "^3.10.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^25.0.9",
|
|
24
|
+
"typescript": "^5.9.3",
|
|
25
|
+
"vitest": "^4.0.17"
|
|
26
|
+
}
|
|
27
|
+
}
|