ts-visio 1.10.0 → 1.11.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/dist/Page.js CHANGED
@@ -113,6 +113,7 @@ class Page {
113
113
  // In a real scenario, we might want to re-read the shape from disk to get full defaults
114
114
  const internalStub = (0, StubHelpers_1.createVisioShapeStub)({
115
115
  ID: newId,
116
+ Type: props.type,
116
117
  Text: props.text,
117
118
  Cells: {
118
119
  'Width': props.width,
package/dist/Shape.d.ts CHANGED
@@ -23,6 +23,16 @@ export declare class Shape {
23
23
  constructor(internalShape: VisioShape, pageId: string, pkg: VisioPackage, modifier?: ShapeModifier);
24
24
  get id(): string;
25
25
  get name(): string;
26
+ /**
27
+ * The shape's Type attribute — `'Group'` for group shapes, `'Shape'` (or `undefined`
28
+ * normalised to `'Shape'`) for regular shapes.
29
+ */
30
+ get type(): string;
31
+ /**
32
+ * `true` if this shape is a Group (i.e. it can contain nested child shapes).
33
+ * Use `shape.getChildren()` to retrieve those children.
34
+ */
35
+ get isGroup(): boolean;
26
36
  get text(): string;
27
37
  setText(newText: string): Promise<void>;
28
38
  get width(): number;
@@ -73,6 +83,20 @@ export declare class Shape {
73
83
  * Returns an empty array if the shape has no layer assignment.
74
84
  */
75
85
  getLayerIndices(): number[];
86
+ /**
87
+ * Return the direct child shapes of this group.
88
+ * Returns an empty array for non-group shapes or groups with no children.
89
+ *
90
+ * Only direct children are returned — grandchildren are accessible by calling
91
+ * `getChildren()` on the child shape.
92
+ *
93
+ * @example
94
+ * const group = await page.addShape({ text: 'G', x: 5, y: 5, width: 4, height: 4, type: 'Group' });
95
+ * await page.addShape({ text: 'Child A', x: 1, y: 1, width: 1, height: 1 }, group.id);
96
+ * await page.addShape({ text: 'Child B', x: 2, y: 1, width: 1, height: 1 }, group.id);
97
+ * group.getChildren(); // → [Shape('Child A'), Shape('Child B')]
98
+ */
99
+ getChildren(): Shape[];
76
100
  /** Current rotation angle in degrees (0 if no Angle cell is set). */
77
101
  get angle(): number;
78
102
  /**
package/dist/Shape.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Shape = void 0;
4
4
  const ShapeModifier_1 = require("./ShapeModifier");
5
5
  const VisioTypes_1 = require("./types/VisioTypes");
6
+ const VisioConstants_1 = require("./core/VisioConstants");
6
7
  /** Round a coordinate to 10 decimal places to prevent float-to-string-to-float precision drift. */
7
8
  function fmtCoord(n) {
8
9
  return parseFloat(n.toFixed(10)).toString();
@@ -20,6 +21,20 @@ class Shape {
20
21
  get name() {
21
22
  return this.internalShape.Name;
22
23
  }
24
+ /**
25
+ * The shape's Type attribute — `'Group'` for group shapes, `'Shape'` (or `undefined`
26
+ * normalised to `'Shape'`) for regular shapes.
27
+ */
28
+ get type() {
29
+ return this.internalShape.Type ?? 'Shape';
30
+ }
31
+ /**
32
+ * `true` if this shape is a Group (i.e. it can contain nested child shapes).
33
+ * Use `shape.getChildren()` to retrieve those children.
34
+ */
35
+ get isGroup() {
36
+ return this.internalShape.Type === VisioConstants_1.SHAPE_TYPES.Group;
37
+ }
23
38
  get text() {
24
39
  return this.internalShape.Text || '';
25
40
  }
@@ -139,6 +154,23 @@ class Shape {
139
154
  getLayerIndices() {
140
155
  return this.modifier.getShapeLayerIndices(this.pageId, this.id);
141
156
  }
157
+ /**
158
+ * Return the direct child shapes of this group.
159
+ * Returns an empty array for non-group shapes or groups with no children.
160
+ *
161
+ * Only direct children are returned — grandchildren are accessible by calling
162
+ * `getChildren()` on the child shape.
163
+ *
164
+ * @example
165
+ * const group = await page.addShape({ text: 'G', x: 5, y: 5, width: 4, height: 4, type: 'Group' });
166
+ * await page.addShape({ text: 'Child A', x: 1, y: 1, width: 1, height: 1 }, group.id);
167
+ * await page.addShape({ text: 'Child B', x: 2, y: 1, width: 1, height: 1 }, group.id);
168
+ * group.getChildren(); // → [Shape('Child A'), Shape('Child B')]
169
+ */
170
+ getChildren() {
171
+ const children = this.modifier.getShapeChildren(this.pageId, this.id);
172
+ return children.map(c => new Shape(c, this.pageId, this.pkg, this.modifier));
173
+ }
142
174
  /** Current rotation angle in degrees (0 if no Angle cell is set). */
143
175
  get angle() {
144
176
  const cell = this.internalShape.Cells['Angle'];
@@ -185,7 +217,7 @@ class Shape {
185
217
  return this;
186
218
  }
187
219
  async addMember(memberShape) {
188
- await this.modifier.addRelationship(this.pageId, this.id, memberShape.id, 'Container');
220
+ await this.modifier.addRelationship(this.pageId, this.id, memberShape.id, VisioConstants_1.STRUCT_RELATIONSHIP_TYPES.Container);
189
221
  return this;
190
222
  }
191
223
  async addListItem(item) {
@@ -2,6 +2,7 @@ import { VisioPackage } from './VisioPackage';
2
2
  import { HorzAlign, VertAlign } from './utils/StyleHelpers';
3
3
  import { NewShapeProps, ConnectorStyle, ConnectionTarget, ConnectionPointDef } from './types/VisioTypes';
4
4
  import type { ShapeData, ShapeHyperlink } from './Shape';
5
+ import type { VisioShape } from './types/VisioTypes';
5
6
  export declare class ShapeModifier {
6
7
  private pkg;
7
8
  addContainer(pageId: string, props: NewShapeProps): Promise<string>;
@@ -128,6 +129,11 @@ export declare class ShapeModifier {
128
129
  * Returns an empty array if the shape has no layer assignment.
129
130
  */
130
131
  getShapeLayerIndices(pageId: string, shapeId: string): number[];
132
+ /**
133
+ * Return the direct child shapes of a group or container shape.
134
+ * Returns an empty array for non-group shapes or shapes with no children.
135
+ */
136
+ getShapeChildren(pageId: string, shapeId: string): VisioShape[];
131
137
  }
132
138
  export interface ShapeStyle {
133
139
  fillColor?: string;
@@ -6,6 +6,7 @@ const StyleHelpers_1 = require("./utils/StyleHelpers");
6
6
  const VisioConstants_1 = require("./core/VisioConstants");
7
7
  const VisioTypes_1 = require("./types/VisioTypes");
8
8
  const ConnectionPointBuilder_1 = require("./shapes/ConnectionPointBuilder");
9
+ const ShapeReader_1 = require("./ShapeReader");
9
10
  const ForeignShapeBuilder_1 = require("./shapes/ForeignShapeBuilder");
10
11
  const ShapeBuilder_1 = require("./shapes/ShapeBuilder");
11
12
  const ConnectorBuilder_1 = require("./shapes/ConnectorBuilder");
@@ -230,9 +231,9 @@ class ShapeModifier {
230
231
  if (!Array.isArray(shape.Section))
231
232
  shape.Section = [shape.Section];
232
233
  // Find or create Connection section
233
- let connSection = shape.Section.find((s) => s['@_N'] === 'Connection');
234
+ let connSection = shape.Section.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.Connection);
234
235
  if (!connSection) {
235
- connSection = { '@_N': 'Connection', Row: [] };
236
+ connSection = { '@_N': VisioConstants_1.SECTION_NAMES.Connection, Row: [] };
236
237
  shape.Section.push(connSection);
237
238
  }
238
239
  if (!connSection.Row)
@@ -282,7 +283,7 @@ class ShapeModifier {
282
283
  newId = this.getNextId(parsed);
283
284
  }
284
285
  let newShape;
285
- if (props.type === 'Foreign' && props.imgRelId) {
286
+ if (props.type === VisioConstants_1.SHAPE_TYPES.Foreign && props.imgRelId) {
286
287
  newShape = ForeignShapeBuilder_1.ForeignShapeBuilder.createImageShapeObject(newId, props.imgRelId, props);
287
288
  // Text for foreign shapes? Usually none, but we can support it.
288
289
  if (props.text !== undefined && props.text !== null) {
@@ -311,8 +312,8 @@ class ShapeModifier {
311
312
  parent.Shapes.Shape = parent.Shapes.Shape ? [parent.Shapes.Shape] : [];
312
313
  }
313
314
  // Mark parent as Group if not already
314
- if (parent['@_Type'] !== 'Group') {
315
- parent['@_Type'] = 'Group';
315
+ if (parent['@_Type'] !== VisioConstants_1.SHAPE_TYPES.Group) {
316
+ parent['@_Type'] = VisioConstants_1.SHAPE_TYPES.Group;
316
317
  }
317
318
  parent.Shapes.Shape.push(newShape);
318
319
  }
@@ -397,7 +398,7 @@ class ShapeModifier {
397
398
  // Update/Add Fill
398
399
  if (style.fillColor) {
399
400
  // Remove existing Fill section if any (simplified: assuming IX=0)
400
- shape.Section = shape.Section.filter((s) => s['@_N'] !== 'Fill');
401
+ shape.Section = shape.Section.filter((s) => s['@_N'] !== VisioConstants_1.SECTION_NAMES.Fill);
401
402
  shape.Section.push((0, StyleHelpers_1.createFillSection)(style.fillColor));
402
403
  }
403
404
  // Update/Add Line
@@ -405,7 +406,7 @@ class ShapeModifier {
405
406
  || style.lineWeight !== undefined
406
407
  || style.linePattern !== undefined;
407
408
  if (hasLineProps) {
408
- shape.Section = shape.Section.filter((s) => s['@_N'] !== 'Line');
409
+ shape.Section = shape.Section.filter((s) => s['@_N'] !== VisioConstants_1.SECTION_NAMES.Line);
409
410
  shape.Section.push((0, StyleHelpers_1.createLineSection)({
410
411
  color: style.lineColor,
411
412
  weight: style.lineWeight !== undefined ? (style.lineWeight / 72).toString() : undefined,
@@ -421,7 +422,7 @@ class ShapeModifier {
421
422
  || style.fontSize !== undefined
422
423
  || style.fontFamily !== undefined;
423
424
  if (hasCharProps) {
424
- shape.Section = shape.Section.filter((s) => s['@_N'] !== 'Character');
425
+ shape.Section = shape.Section.filter((s) => s['@_N'] !== VisioConstants_1.SECTION_NAMES.Character);
425
426
  shape.Section.push((0, StyleHelpers_1.createCharacterSection)({
426
427
  bold: style.bold,
427
428
  italic: style.italic,
@@ -438,7 +439,7 @@ class ShapeModifier {
438
439
  || style.spaceAfter !== undefined
439
440
  || style.lineSpacing !== undefined;
440
441
  if (hasParagraphProps) {
441
- shape.Section = shape.Section.filter((s) => s['@_N'] !== 'Paragraph');
442
+ shape.Section = shape.Section.filter((s) => s['@_N'] !== VisioConstants_1.SECTION_NAMES.Paragraph);
442
443
  shape.Section.push((0, StyleHelpers_1.createParagraphSection)({
443
444
  horzAlign: style.horzAlign,
444
445
  spaceBefore: style.spaceBefore,
@@ -452,7 +453,7 @@ class ShapeModifier {
452
453
  || style.textMarginLeft !== undefined
453
454
  || style.textMarginRight !== undefined;
454
455
  if (hasTextBlockProps) {
455
- shape.Section = shape.Section.filter((s) => s['@_N'] !== 'TextBlock');
456
+ shape.Section = shape.Section.filter((s) => s['@_N'] !== VisioConstants_1.SECTION_NAMES.TextBlock);
456
457
  shape.Section.push((0, StyleHelpers_1.createTextBlockSection)({
457
458
  topMargin: style.textMarginTop,
458
459
  bottomMargin: style.textMarginBottom,
@@ -570,7 +571,7 @@ class ShapeModifier {
570
571
  if (shape.Section) {
571
572
  const sections = Array.isArray(shape.Section) ? shape.Section : [shape.Section];
572
573
  for (const section of sections) {
573
- if (section['@_N'] !== 'Geometry' || !section.Row)
574
+ if (section['@_N'] !== VisioConstants_1.SECTION_NAMES.Geometry || !section.Row)
574
575
  continue;
575
576
  const rows = Array.isArray(section.Row) ? section.Row : [section.Row];
576
577
  for (const row of rows) {
@@ -627,9 +628,9 @@ class ShapeModifier {
627
628
  if (!Array.isArray(shape.Section))
628
629
  shape.Section = [shape.Section];
629
630
  // Find or Create Property Section
630
- let propSection = shape.Section.find((s) => s['@_N'] === 'Property');
631
+ let propSection = shape.Section.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.Property);
631
632
  if (!propSection) {
632
- propSection = { '@_N': 'Property', Row: [] };
633
+ propSection = { '@_N': VisioConstants_1.SECTION_NAMES.Property, Row: [] };
633
634
  shape.Section.push(propSection);
634
635
  }
635
636
  // Ensure Row array exists
@@ -681,7 +682,7 @@ class ShapeModifier {
681
682
  }
682
683
  // Ensure Section array exists
683
684
  const sections = shape.Section ? (Array.isArray(shape.Section) ? shape.Section : [shape.Section]) : [];
684
- const propSection = sections.find((s) => s['@_N'] === 'Property');
685
+ const propSection = sections.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.Property);
685
686
  if (!propSection) {
686
687
  throw new Error(`Property definition 'Prop.${name}' does not exist on shape ${shapeId}. Call addPropertyDefinition first.`);
687
688
  }
@@ -770,7 +771,7 @@ class ShapeModifier {
770
771
  return [];
771
772
  const relsArray = Array.isArray(rels) ? rels : [rels];
772
773
  return relsArray
773
- .filter((r) => r['@_Type'] === 'Container' && r['@_ShapeID'] === containerId)
774
+ .filter((r) => r['@_Type'] === VisioConstants_1.STRUCT_RELATIONSHIP_TYPES.Container && r['@_ShapeID'] === containerId)
774
775
  .map((r) => r['@_RelatedShapeID']);
775
776
  }
776
777
  async reorderShape(pageId, shapeId, position) {
@@ -805,7 +806,7 @@ class ShapeModifier {
805
806
  const getUserVal = (name, def) => {
806
807
  if (!listShape.Section)
807
808
  return def;
808
- const userSec = listShape.Section.find((s) => s['@_N'] === 'User');
809
+ const userSec = listShape.Section.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.User);
809
810
  if (!userSec || !userSec.Row)
810
811
  return def;
811
812
  const rows = Array.isArray(userSec.Row) ? userSec.Row : [userSec.Row];
@@ -850,7 +851,7 @@ class ShapeModifier {
850
851
  // 3. Update Item Position
851
852
  await this.updateShapePosition(pageId, itemId, newX, newY);
852
853
  // 4. Add Relationship
853
- await this.addRelationship(pageId, listId, itemId, 'Container');
854
+ await this.addRelationship(pageId, listId, itemId, VisioConstants_1.STRUCT_RELATIONSHIP_TYPES.Container);
854
855
  // 5. Resize List Container
855
856
  await this.resizeContainerToFit(pageId, listId, 0.25);
856
857
  }
@@ -990,9 +991,9 @@ class ShapeModifier {
990
991
  if (!Array.isArray(shape.Section))
991
992
  shape.Section = [shape.Section];
992
993
  // Find or Create LayerMem Section
993
- let memSection = shape.Section.find((s) => s['@_N'] === 'LayerMem');
994
+ let memSection = shape.Section.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.LayerMem);
994
995
  if (!memSection) {
995
- memSection = { '@_N': 'LayerMem', Row: [] };
996
+ memSection = { '@_N': VisioConstants_1.SECTION_NAMES.LayerMem, Row: [] };
996
997
  shape.Section.push(memSection);
997
998
  }
998
999
  // Ensure Row array
@@ -1073,7 +1074,7 @@ class ShapeModifier {
1073
1074
  if (!shape.Section)
1074
1075
  return result;
1075
1076
  const sections = Array.isArray(shape.Section) ? shape.Section : [shape.Section];
1076
- const propSection = sections.find((s) => s['@_N'] === 'Property');
1077
+ const propSection = sections.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.Property);
1077
1078
  if (!propSection?.Row)
1078
1079
  return result;
1079
1080
  const rows = Array.isArray(propSection.Row) ? propSection.Row : [propSection.Row];
@@ -1188,7 +1189,7 @@ class ShapeModifier {
1188
1189
  if (!shape.Section)
1189
1190
  return [];
1190
1191
  const sections = Array.isArray(shape.Section) ? shape.Section : [shape.Section];
1191
- const memSection = sections.find((s) => s['@_N'] === 'LayerMem');
1192
+ const memSection = sections.find((s) => s['@_N'] === VisioConstants_1.SECTION_NAMES.LayerMem);
1192
1193
  if (!memSection?.Row)
1193
1194
  return [];
1194
1195
  const rows = Array.isArray(memSection.Row) ? memSection.Row : [memSection.Row];
@@ -1205,5 +1206,14 @@ class ShapeModifier {
1205
1206
  .map((s) => parseInt(s))
1206
1207
  .filter((n) => !isNaN(n));
1207
1208
  }
1209
+ /**
1210
+ * Return the direct child shapes of a group or container shape.
1211
+ * Returns an empty array for non-group shapes or shapes with no children.
1212
+ */
1213
+ getShapeChildren(pageId, shapeId) {
1214
+ const pagePath = this.getPagePath(pageId);
1215
+ const reader = new ShapeReader_1.ShapeReader(this.pkg);
1216
+ return reader.readChildShapes(pagePath, shapeId);
1217
+ }
1208
1218
  }
1209
1219
  exports.ShapeModifier = ShapeModifier;
@@ -25,6 +25,12 @@ export declare class ShapeReader {
25
25
  /** Decode a Visio ToPart integer string to a ConnectionTarget. */
26
26
  private decodeToPart;
27
27
  private gatherShapes;
28
+ /**
29
+ * Return the direct child shapes of a group or container shape.
30
+ * Returns an empty array if the shape has no children or does not exist.
31
+ */
32
+ readChildShapes(path: string, parentId: string): VisioShape[];
28
33
  private findShapeById;
34
+ private findRawShape;
29
35
  private parseShape;
30
36
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ShapeReader = void 0;
4
4
  const fast_xml_parser_1 = require("fast-xml-parser");
5
5
  const VisioParsers_1 = require("./utils/VisioParsers");
6
+ const VisioConstants_1 = require("./core/VisioConstants");
6
7
  class ShapeReader {
7
8
  constructor(pkg) {
8
9
  this.pkg = pkg;
@@ -138,7 +139,7 @@ class ShapeReader {
138
139
  let lineWeight;
139
140
  let linePattern;
140
141
  for (const sec of sections) {
141
- if (sec['@_N'] === 'Line') {
142
+ if (sec['@_N'] === VisioConstants_1.SECTION_NAMES.Line) {
142
143
  const lineCells = (0, VisioParsers_1.parseCells)(sec);
143
144
  if (lineCells['LineColor']?.V)
144
145
  lineColor = lineCells['LineColor'].V;
@@ -190,12 +191,37 @@ class ShapeReader {
190
191
  }
191
192
  }
192
193
  }
194
+ /**
195
+ * Return the direct child shapes of a group or container shape.
196
+ * Returns an empty array if the shape has no children or does not exist.
197
+ */
198
+ readChildShapes(path, parentId) {
199
+ let content;
200
+ try {
201
+ content = this.pkg.getFileText(path);
202
+ }
203
+ catch {
204
+ return [];
205
+ }
206
+ const parsed = this.parser.parse(content);
207
+ const shapesData = parsed.PageContents?.Shapes?.Shape;
208
+ if (!shapesData)
209
+ return [];
210
+ const rawParent = this.findRawShape((0, VisioParsers_1.asArray)(shapesData), parentId);
211
+ if (!rawParent?.Shapes?.Shape)
212
+ return [];
213
+ return (0, VisioParsers_1.asArray)(rawParent.Shapes.Shape).map((s) => this.parseShape(s));
214
+ }
193
215
  findShapeById(rawShapes, shapeId) {
216
+ const raw = this.findRawShape(rawShapes, shapeId);
217
+ return raw ? this.parseShape(raw) : undefined;
218
+ }
219
+ findRawShape(rawShapes, shapeId) {
194
220
  for (const s of rawShapes) {
195
221
  if (s['@_ID'] === shapeId)
196
- return this.parseShape(s);
222
+ return s;
197
223
  if (s.Shapes?.Shape) {
198
- const found = this.findShapeById((0, VisioParsers_1.asArray)(s.Shapes.Shape), shapeId);
224
+ const found = this.findRawShape((0, VisioParsers_1.asArray)(s.Shapes.Shape), shapeId);
199
225
  if (found)
200
226
  return found;
201
227
  }
@@ -21,6 +21,35 @@ export declare const RELATIONSHIP_TYPES: {
21
21
  readonly CORE_PROPERTIES: "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
22
22
  readonly EXTENDED_PROPERTIES: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
23
23
  };
24
+ /** Visio shape `Type` attribute values. */
25
+ export declare const SHAPE_TYPES: {
26
+ readonly Shape: "Shape";
27
+ readonly Group: "Group";
28
+ readonly Foreign: "Foreign";
29
+ };
30
+ /**
31
+ * Visio ShapeSheet section names (the `N` attribute on `<Section>` elements).
32
+ * Used when finding or filtering sections by name in page/master XML.
33
+ */
34
+ export declare const SECTION_NAMES: {
35
+ readonly Line: "Line";
36
+ readonly Fill: "Fill";
37
+ readonly Character: "Character";
38
+ readonly Paragraph: "Paragraph";
39
+ readonly TextBlock: "TextBlock";
40
+ readonly Geometry: "Geometry";
41
+ readonly Connection: "Connection";
42
+ readonly Property: "Property";
43
+ readonly User: "User";
44
+ readonly LayerMem: "LayerMem";
45
+ };
46
+ /**
47
+ * Structural relationship types stored in `<Relationship>` elements
48
+ * inside Visio page XML (distinct from OPC `.rels` relationship types).
49
+ */
50
+ export declare const STRUCT_RELATIONSHIP_TYPES: {
51
+ readonly Container: "Container";
52
+ };
24
53
  export declare const CONTENT_TYPES: {
25
54
  readonly PNG: "image/png";
26
55
  readonly JPEG: "image/jpeg";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CONTENT_TYPES = exports.RELATIONSHIP_TYPES = exports.XML_NAMESPACES = void 0;
3
+ exports.CONTENT_TYPES = exports.STRUCT_RELATIONSHIP_TYPES = exports.SECTION_NAMES = exports.SHAPE_TYPES = exports.RELATIONSHIP_TYPES = exports.XML_NAMESPACES = void 0;
4
4
  exports.XML_NAMESPACES = {
5
5
  VISIO_MAIN: 'http://schemas.microsoft.com/office/visio/2012/main',
6
6
  RELATIONSHIPS: 'http://schemas.openxmlformats.org/package/2006/relationships',
@@ -24,6 +24,35 @@ exports.RELATIONSHIP_TYPES = {
24
24
  CORE_PROPERTIES: 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties',
25
25
  EXTENDED_PROPERTIES: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties'
26
26
  };
27
+ /** Visio shape `Type` attribute values. */
28
+ exports.SHAPE_TYPES = {
29
+ Shape: 'Shape',
30
+ Group: 'Group',
31
+ Foreign: 'Foreign',
32
+ };
33
+ /**
34
+ * Visio ShapeSheet section names (the `N` attribute on `<Section>` elements).
35
+ * Used when finding or filtering sections by name in page/master XML.
36
+ */
37
+ exports.SECTION_NAMES = {
38
+ Line: 'Line',
39
+ Fill: 'Fill',
40
+ Character: 'Character',
41
+ Paragraph: 'Paragraph',
42
+ TextBlock: 'TextBlock',
43
+ Geometry: 'Geometry',
44
+ Connection: 'Connection',
45
+ Property: 'Property',
46
+ User: 'User',
47
+ LayerMem: 'LayerMem',
48
+ };
49
+ /**
50
+ * Structural relationship types stored in `<Relationship>` elements
51
+ * inside Visio page XML (distinct from OPC `.rels` relationship types).
52
+ */
53
+ exports.STRUCT_RELATIONSHIP_TYPES = {
54
+ Container: 'Container',
55
+ };
27
56
  exports.CONTENT_TYPES = {
28
57
  PNG: 'image/png',
29
58
  JPEG: 'image/jpeg',
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VisioValidator = void 0;
4
4
  const fast_xml_parser_1 = require("fast-xml-parser");
5
+ const VisioConstants_1 = require("./VisioConstants");
5
6
  // Known Visio section names per Microsoft schema
6
7
  const VALID_SECTION_NAMES = new Set([
7
8
  'Geometry', 'Character', 'Paragraph', 'Tabs', 'Scratch', 'Connection',
@@ -241,7 +242,7 @@ class VisioValidator {
241
242
  validateImageShapes(pkg, pageId, parsed, pagePath, errors, warnings) {
242
243
  const shapes = this.getAllShapes(parsed);
243
244
  for (const shape of shapes) {
244
- if (shape['@_Type'] !== 'Foreign')
245
+ if (shape['@_Type'] !== VisioConstants_1.SHAPE_TYPES.Foreign)
245
246
  continue;
246
247
  if (!shape.ForeignData) {
247
248
  warnings.push(`${pagePath}: Foreign shape ${shape['@_ID']} missing ForeignData`);
@@ -4,6 +4,7 @@ exports.ShapeBuilder = void 0;
4
4
  const StyleHelpers_1 = require("../utils/StyleHelpers");
5
5
  const GeometryBuilder_1 = require("./GeometryBuilder");
6
6
  const ConnectionPointBuilder_1 = require("./ConnectionPointBuilder");
7
+ const VisioConstants_1 = require("../core/VisioConstants");
7
8
  class ShapeBuilder {
8
9
  static createStandardShape(id, props) {
9
10
  // Validate dimensions
@@ -14,7 +15,7 @@ class ShapeBuilder {
14
15
  '@_ID': id,
15
16
  '@_NameU': `Sheet.${id}`,
16
17
  '@_Name': `Sheet.${id}`,
17
- '@_Type': props.type || 'Shape',
18
+ '@_Type': props.type || VisioConstants_1.SHAPE_TYPES.Shape,
18
19
  Cell: [
19
20
  { '@_N': 'PinX', '@_V': props.x.toString() },
20
21
  { '@_N': 'PinY', '@_V': props.y.toString() },
@@ -103,7 +104,7 @@ class ShapeBuilder {
103
104
  }
104
105
  // Add Geometry
105
106
  // Only if NOT a Group AND NOT a Master Instance
106
- if (props.type !== 'Group' && !props.masterId) {
107
+ if (props.type !== VisioConstants_1.SHAPE_TYPES.Group && !props.masterId) {
107
108
  shape.Section.push(GeometryBuilder_1.GeometryBuilder.build(props));
108
109
  }
109
110
  // Handle Text if provided
@@ -2,6 +2,7 @@ import { VisioShape } from '../types/VisioTypes';
2
2
  export declare function createVisioShapeStub(props: {
3
3
  ID: string;
4
4
  Name?: string;
5
+ Type?: string;
5
6
  Text?: string;
6
7
  Cells?: Record<string, string | number>;
7
8
  }): VisioShape;
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createVisioShapeStub = createVisioShapeStub;
4
+ const VisioConstants_1 = require("../core/VisioConstants");
4
5
  function createVisioShapeStub(props) {
5
6
  return {
6
7
  ID: props.ID,
7
8
  Name: props.Name || `Sheet.${props.ID}`,
8
- Type: 'Shape',
9
+ Type: props.Type ?? VisioConstants_1.SHAPE_TYPES.Shape,
9
10
  Text: props.Text,
10
11
  Cells: Object.entries(props.Cells || {}).reduce((acc, [k, v]) => {
11
12
  acc[k] = { N: k, V: v.toString() };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-visio",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {