ts-visio 1.0.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -3
- package/dist/Layer.d.ts +3 -1
- package/dist/Layer.js +6 -7
- package/dist/Page.d.ts +12 -0
- package/dist/Page.js +35 -12
- package/dist/Shape.d.ts +47 -2
- package/dist/Shape.js +119 -78
- package/dist/ShapeModifier.d.ts +53 -0
- package/dist/ShapeModifier.js +451 -267
- package/dist/ShapeReader.d.ts +12 -0
- package/dist/ShapeReader.js +59 -3
- package/dist/VisioDocument.d.ts +10 -0
- package/dist/VisioDocument.js +20 -1
- package/dist/VisioPackage.d.ts +1 -0
- package/dist/VisioPackage.js +7 -0
- package/dist/core/MasterManager.js +1 -1
- package/dist/core/MediaConstants.js +11 -2
- package/dist/core/MediaManager.js +8 -16
- package/dist/core/PageManager.d.ts +8 -1
- package/dist/core/PageManager.js +75 -16
- package/dist/core/RelsManager.js +4 -11
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/shapes/ConnectorBuilder.js +8 -9
- package/dist/shapes/ContainerBuilder.js +8 -6
- package/dist/shapes/ForeignShapeBuilder.js +9 -6
- package/dist/shapes/ShapeBuilder.js +15 -7
- package/dist/types/VisioTypes.d.ts +12 -0
- package/dist/utils/StyleHelpers.d.ts +21 -4
- package/dist/utils/StyleHelpers.js +52 -27
- package/dist/utils/XmlHelper.d.ts +39 -0
- package/dist/utils/XmlHelper.js +56 -0
- package/package.json +2 -2
|
@@ -18,8 +18,8 @@ class ShapeBuilder {
|
|
|
18
18
|
{ '@_N': 'PinY', '@_V': props.y.toString() },
|
|
19
19
|
{ '@_N': 'Width', '@_V': props.width.toString() },
|
|
20
20
|
{ '@_N': 'Height', '@_V': props.height.toString() },
|
|
21
|
-
{ '@_N': 'LocPinX', '@_V': (props.width / 2).toString() },
|
|
22
|
-
{ '@_N': 'LocPinY', '@_V': (props.height / 2).toString() }
|
|
21
|
+
{ '@_N': 'LocPinX', '@_V': (props.width / 2).toString(), '@_F': 'Width*0.5' },
|
|
22
|
+
{ '@_N': 'LocPinY', '@_V': (props.height / 2).toString(), '@_F': 'Height*0.5' }
|
|
23
23
|
],
|
|
24
24
|
Section: []
|
|
25
25
|
// Text added at end by caller or we can do it here if props.text is final
|
|
@@ -36,12 +36,20 @@ class ShapeBuilder {
|
|
|
36
36
|
weight: '0.01'
|
|
37
37
|
}));
|
|
38
38
|
}
|
|
39
|
-
if (props.fontColor || props.bold) {
|
|
39
|
+
if (props.fontColor || props.bold || props.fontSize !== undefined || props.fontFamily !== undefined) {
|
|
40
40
|
shape.Section.push((0, StyleHelpers_1.createCharacterSection)({
|
|
41
41
|
bold: props.bold,
|
|
42
|
-
color: props.fontColor
|
|
42
|
+
color: props.fontColor,
|
|
43
|
+
fontSize: props.fontSize,
|
|
44
|
+
fontFamily: props.fontFamily,
|
|
43
45
|
}));
|
|
44
46
|
}
|
|
47
|
+
if (props.horzAlign !== undefined) {
|
|
48
|
+
shape.Section.push((0, StyleHelpers_1.createParagraphSection)(props.horzAlign));
|
|
49
|
+
}
|
|
50
|
+
if (props.verticalAlign !== undefined) {
|
|
51
|
+
shape.Cell.push({ '@_N': 'VerticalAlign', '@_V': (0, StyleHelpers_1.vertAlignValue)(props.verticalAlign) });
|
|
52
|
+
}
|
|
45
53
|
// Add Geometry
|
|
46
54
|
// Only if NOT a Group AND NOT a Master Instance
|
|
47
55
|
if (props.type !== 'Group' && !props.masterId) {
|
|
@@ -51,9 +59,9 @@ class ShapeBuilder {
|
|
|
51
59
|
Cell: [{ '@_N': 'NoFill', '@_V': props.fillColor ? '0' : '1' }],
|
|
52
60
|
Row: [
|
|
53
61
|
{ '@_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() }] },
|
|
62
|
+
{ '@_T': 'LineTo', '@_IX': '2', Cell: [{ '@_N': 'X', '@_V': props.width.toString(), '@_F': 'Width' }, { '@_N': 'Y', '@_V': '0' }] },
|
|
63
|
+
{ '@_T': 'LineTo', '@_IX': '3', Cell: [{ '@_N': 'X', '@_V': props.width.toString(), '@_F': 'Width' }, { '@_N': 'Y', '@_V': props.height.toString(), '@_F': 'Height' }] },
|
|
64
|
+
{ '@_T': 'LineTo', '@_IX': '4', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': props.height.toString(), '@_F': 'Height' }] },
|
|
57
65
|
{ '@_T': 'LineTo', '@_IX': '5', Cell: [{ '@_N': 'X', '@_V': '0' }, { '@_N': 'Y', '@_V': '0' }] }
|
|
58
66
|
]
|
|
59
67
|
});
|
|
@@ -45,6 +45,10 @@ export interface VisioPage {
|
|
|
45
45
|
ID: string;
|
|
46
46
|
Name: string;
|
|
47
47
|
NameU?: string;
|
|
48
|
+
/** Resolved OPC part path (e.g. "visio/pages/page2.xml"). When present,
|
|
49
|
+
* this takes precedence over the ID-derived fallback path so that loaded
|
|
50
|
+
* files with non-sequential page filenames are handled correctly. */
|
|
51
|
+
xmlPath?: string;
|
|
48
52
|
Shapes: VisioShape[];
|
|
49
53
|
Connects: VisioConnect[];
|
|
50
54
|
isBackground?: boolean;
|
|
@@ -78,6 +82,14 @@ export interface NewShapeProps {
|
|
|
78
82
|
fillColor?: string;
|
|
79
83
|
fontColor?: string;
|
|
80
84
|
bold?: boolean;
|
|
85
|
+
/** Font size in points (e.g. 14 for 14pt). */
|
|
86
|
+
fontSize?: number;
|
|
87
|
+
/** Font family name (e.g. "Arial", "Times New Roman"). */
|
|
88
|
+
fontFamily?: string;
|
|
89
|
+
/** Horizontal text alignment within the shape. */
|
|
90
|
+
horzAlign?: 'left' | 'center' | 'right' | 'justify';
|
|
91
|
+
/** Vertical text alignment within the shape. */
|
|
92
|
+
verticalAlign?: 'top' | 'middle' | 'bottom';
|
|
81
93
|
type?: string;
|
|
82
94
|
masterId?: string;
|
|
83
95
|
imgRelId?: string;
|
|
@@ -15,16 +15,33 @@ export declare const ArrowHeads: {
|
|
|
15
15
|
CrowsFoot: string;
|
|
16
16
|
One: string;
|
|
17
17
|
};
|
|
18
|
+
declare const HORZ_ALIGN_VALUES: {
|
|
19
|
+
readonly left: "0";
|
|
20
|
+
readonly center: "1";
|
|
21
|
+
readonly right: "2";
|
|
22
|
+
readonly justify: "3";
|
|
23
|
+
};
|
|
24
|
+
declare const VERT_ALIGN_VALUES: {
|
|
25
|
+
readonly top: "0";
|
|
26
|
+
readonly middle: "1";
|
|
27
|
+
readonly bottom: "2";
|
|
28
|
+
};
|
|
29
|
+
export type HorzAlign = keyof typeof HORZ_ALIGN_VALUES;
|
|
30
|
+
export type VertAlign = keyof typeof VERT_ALIGN_VALUES;
|
|
31
|
+
export declare function horzAlignValue(align: HorzAlign): string;
|
|
32
|
+
export declare function vertAlignValue(align: VertAlign): string;
|
|
18
33
|
export declare function createCharacterSection(props: {
|
|
19
34
|
bold?: boolean;
|
|
20
35
|
color?: string;
|
|
36
|
+
/** Font size in points (e.g. 12 for 12pt). Stored internally as inches (pt / 72). */
|
|
37
|
+
fontSize?: number;
|
|
38
|
+
/** Font family name (e.g. "Arial"). Uses FONT() formula for portability. */
|
|
39
|
+
fontFamily?: string;
|
|
21
40
|
}): VisioSection;
|
|
41
|
+
export declare function createParagraphSection(horzAlign: HorzAlign): VisioSection;
|
|
22
42
|
export declare function createLineSection(props: {
|
|
23
43
|
color?: string;
|
|
24
44
|
pattern?: string;
|
|
25
45
|
weight?: string;
|
|
26
|
-
beginArrow?: string;
|
|
27
|
-
beginArrowSize?: string;
|
|
28
|
-
endArrow?: string;
|
|
29
|
-
endArrowSize?: string;
|
|
30
46
|
}): VisioSection;
|
|
47
|
+
export {};
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ArrowHeads = void 0;
|
|
4
4
|
exports.createFillSection = createFillSection;
|
|
5
|
+
exports.horzAlignValue = horzAlignValue;
|
|
6
|
+
exports.vertAlignValue = vertAlignValue;
|
|
5
7
|
exports.createCharacterSection = createCharacterSection;
|
|
8
|
+
exports.createParagraphSection = createParagraphSection;
|
|
6
9
|
exports.createLineSection = createLineSection;
|
|
7
10
|
const hexToRgb = (hex) => {
|
|
8
11
|
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
@@ -35,32 +38,66 @@ exports.ArrowHeads = {
|
|
|
35
38
|
One: '24', // Visio "One" (Dash) - Approximate, or '26'
|
|
36
39
|
// There are many variants, but 29 is the standard "Fork"
|
|
37
40
|
};
|
|
41
|
+
const HORZ_ALIGN_VALUES = {
|
|
42
|
+
left: '0',
|
|
43
|
+
center: '1',
|
|
44
|
+
right: '2',
|
|
45
|
+
justify: '3',
|
|
46
|
+
};
|
|
47
|
+
const VERT_ALIGN_VALUES = {
|
|
48
|
+
top: '0',
|
|
49
|
+
middle: '1',
|
|
50
|
+
bottom: '2',
|
|
51
|
+
};
|
|
52
|
+
function horzAlignValue(align) {
|
|
53
|
+
return HORZ_ALIGN_VALUES[align];
|
|
54
|
+
}
|
|
55
|
+
function vertAlignValue(align) {
|
|
56
|
+
return VERT_ALIGN_VALUES[align];
|
|
57
|
+
}
|
|
38
58
|
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
59
|
let styleVal = 0;
|
|
48
60
|
if (props.bold) {
|
|
49
|
-
styleVal += 1; //
|
|
61
|
+
styleVal += 1; // Bold bit
|
|
50
62
|
}
|
|
51
|
-
// Default Color is usually 0 (Black) or specific hex
|
|
52
63
|
const colorVal = props.color || '#000000';
|
|
64
|
+
const cells = [
|
|
65
|
+
{ '@_N': 'Color', '@_V': colorVal, '@_F': hexToRgb(colorVal) },
|
|
66
|
+
{ '@_N': 'Style', '@_V': styleVal.toString() },
|
|
67
|
+
];
|
|
68
|
+
if (props.fontSize !== undefined) {
|
|
69
|
+
// Visio stores size in inches internally; @_U="PT" is a display hint for the ShapeSheet UI
|
|
70
|
+
const sizeInInches = props.fontSize / 72;
|
|
71
|
+
cells.push({ '@_N': 'Size', '@_V': sizeInInches.toString(), '@_U': 'PT' });
|
|
72
|
+
}
|
|
73
|
+
if (props.fontFamily !== undefined) {
|
|
74
|
+
// FONT("name") formula lets Visio resolve the font by name at load time.
|
|
75
|
+
// @_V="0" is a safe placeholder (document default font) used before Visio evaluates the formula.
|
|
76
|
+
cells.push({ '@_N': 'Font', '@_V': '0', '@_F': `FONT("${props.fontFamily}")` });
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
cells.push({ '@_N': 'Font', '@_V': '1' }); // Default (Calibri)
|
|
80
|
+
}
|
|
53
81
|
return {
|
|
54
82
|
'@_N': 'Character',
|
|
55
83
|
Row: [
|
|
56
84
|
{
|
|
57
85
|
'@_T': 'Character',
|
|
58
86
|
'@_IX': '0',
|
|
87
|
+
Cell: cells,
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function createParagraphSection(horzAlign) {
|
|
93
|
+
return {
|
|
94
|
+
'@_N': 'Paragraph',
|
|
95
|
+
Row: [
|
|
96
|
+
{
|
|
97
|
+
'@_T': 'Paragraph',
|
|
98
|
+
'@_IX': '0',
|
|
59
99
|
Cell: [
|
|
60
|
-
{ '@_N': '
|
|
61
|
-
{ '@_N': 'Style', '@_V': styleVal.toString() },
|
|
62
|
-
// Size, Font, etc could go here
|
|
63
|
-
{ '@_N': 'Font', '@_V': '1' } // Default font (Calibri usually)
|
|
100
|
+
{ '@_N': 'HorzAlign', '@_V': HORZ_ALIGN_VALUES[horzAlign] },
|
|
64
101
|
]
|
|
65
102
|
}
|
|
66
103
|
]
|
|
@@ -70,24 +107,12 @@ function createLineSection(props) {
|
|
|
70
107
|
const cells = [
|
|
71
108
|
{ '@_N': 'LineColor', '@_V': props.color || '#000000' },
|
|
72
109
|
{ '@_N': 'LinePattern', '@_V': props.pattern || '1' }, // 1 = Solid
|
|
73
|
-
{ '@_N': 'LineWeight', '@_V': props.weight || '0.01' } // ~0.72pt
|
|
110
|
+
{ '@_N': 'LineWeight', '@_V': props.weight || '0.01', '@_U': 'IN' } // ~0.72pt
|
|
74
111
|
];
|
|
75
112
|
// Add RGB Formula for custom colors
|
|
76
113
|
if (props.color) {
|
|
77
114
|
cells[0]['@_F'] = hexToRgb(props.color);
|
|
78
115
|
}
|
|
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
116
|
return {
|
|
92
117
|
'@_N': 'Line',
|
|
93
118
|
Cell: cells
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Standard XMLParser options used across all Visio XML parts.
|
|
4
|
+
*
|
|
5
|
+
* - ignoreDeclaration: false → preserves <?xml?> in the parsed object
|
|
6
|
+
* - ignoreAttributes: false → preserves xmlns, xmlns:r, xml:space, etc.
|
|
7
|
+
* - parseAttributeValue: false → keeps attribute values as strings (avoids
|
|
8
|
+
* numeric coercion on IDs, versions, etc.)
|
|
9
|
+
*/
|
|
10
|
+
export declare const PARSER_OPTIONS: {
|
|
11
|
+
readonly ignoreAttributes: false;
|
|
12
|
+
readonly attributeNamePrefix: "@_";
|
|
13
|
+
readonly ignoreDeclaration: false;
|
|
14
|
+
readonly parseAttributeValue: false;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Standard XMLBuilder options used across all Visio XML parts.
|
|
18
|
+
*
|
|
19
|
+
* - suppressBooleanAttributes: false → always emit attribute="value", never
|
|
20
|
+
* bare attribute (important for Visio attributes like xml:space="preserve")
|
|
21
|
+
*/
|
|
22
|
+
export declare const BUILDER_OPTIONS: {
|
|
23
|
+
readonly ignoreAttributes: false;
|
|
24
|
+
readonly attributeNamePrefix: "@_";
|
|
25
|
+
readonly format: true;
|
|
26
|
+
readonly suppressBooleanAttributes: false;
|
|
27
|
+
};
|
|
28
|
+
export declare function createXmlParser(): XMLParser;
|
|
29
|
+
export declare function createXmlBuilder(): XMLBuilder;
|
|
30
|
+
/**
|
|
31
|
+
* Serialize a parsed XML object to a string, guaranteeing the XML declaration
|
|
32
|
+
* is always present at the top of the output.
|
|
33
|
+
*
|
|
34
|
+
* fast-xml-parser's XMLBuilder re-emits the `?xml` key when it is present in
|
|
35
|
+
* the parsed object (requires ignoreDeclaration: false on the parser side).
|
|
36
|
+
* This function acts as a safety net for cases where the declaration was
|
|
37
|
+
* absent in the source XML or was stripped for any reason.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildXml(builder: XMLBuilder, parsed: unknown): string;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BUILDER_OPTIONS = exports.PARSER_OPTIONS = void 0;
|
|
4
|
+
exports.createXmlParser = createXmlParser;
|
|
5
|
+
exports.createXmlBuilder = createXmlBuilder;
|
|
6
|
+
exports.buildXml = buildXml;
|
|
7
|
+
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
8
|
+
const XML_DECLARATION = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
|
|
9
|
+
/**
|
|
10
|
+
* Standard XMLParser options used across all Visio XML parts.
|
|
11
|
+
*
|
|
12
|
+
* - ignoreDeclaration: false → preserves <?xml?> in the parsed object
|
|
13
|
+
* - ignoreAttributes: false → preserves xmlns, xmlns:r, xml:space, etc.
|
|
14
|
+
* - parseAttributeValue: false → keeps attribute values as strings (avoids
|
|
15
|
+
* numeric coercion on IDs, versions, etc.)
|
|
16
|
+
*/
|
|
17
|
+
exports.PARSER_OPTIONS = {
|
|
18
|
+
ignoreAttributes: false,
|
|
19
|
+
attributeNamePrefix: '@_',
|
|
20
|
+
ignoreDeclaration: false,
|
|
21
|
+
parseAttributeValue: false,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Standard XMLBuilder options used across all Visio XML parts.
|
|
25
|
+
*
|
|
26
|
+
* - suppressBooleanAttributes: false → always emit attribute="value", never
|
|
27
|
+
* bare attribute (important for Visio attributes like xml:space="preserve")
|
|
28
|
+
*/
|
|
29
|
+
exports.BUILDER_OPTIONS = {
|
|
30
|
+
ignoreAttributes: false,
|
|
31
|
+
attributeNamePrefix: '@_',
|
|
32
|
+
format: true,
|
|
33
|
+
suppressBooleanAttributes: false,
|
|
34
|
+
};
|
|
35
|
+
function createXmlParser() {
|
|
36
|
+
return new fast_xml_parser_1.XMLParser(exports.PARSER_OPTIONS);
|
|
37
|
+
}
|
|
38
|
+
function createXmlBuilder() {
|
|
39
|
+
return new fast_xml_parser_1.XMLBuilder(exports.BUILDER_OPTIONS);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Serialize a parsed XML object to a string, guaranteeing the XML declaration
|
|
43
|
+
* is always present at the top of the output.
|
|
44
|
+
*
|
|
45
|
+
* fast-xml-parser's XMLBuilder re-emits the `?xml` key when it is present in
|
|
46
|
+
* the parsed object (requires ignoreDeclaration: false on the parser side).
|
|
47
|
+
* This function acts as a safety net for cases where the declaration was
|
|
48
|
+
* absent in the source XML or was stripped for any reason.
|
|
49
|
+
*/
|
|
50
|
+
function buildXml(builder, parsed) {
|
|
51
|
+
const xml = builder.build(parsed);
|
|
52
|
+
if (xml.trimStart().startsWith('<?xml')) {
|
|
53
|
+
return xml;
|
|
54
|
+
}
|
|
55
|
+
return XML_DECLARATION + '\n' + xml;
|
|
56
|
+
}
|