layoutbridge-spm 0.0.1 → 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.
Files changed (79) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/LICENSE +26 -0
  3. package/README.de.md +318 -0
  4. package/README.md +304 -4
  5. package/THIRD-PARTY-NOTICES.md +2878 -0
  6. package/dist/src/mcp/config.js +125 -0
  7. package/dist/src/mcp/dispatch.js +123 -0
  8. package/dist/src/mcp/license/free-tools.js +16 -0
  9. package/dist/src/mcp/license/gate.js +209 -0
  10. package/dist/src/mcp/license/index.js +96 -0
  11. package/dist/src/mcp/license/instance-name.js +56 -0
  12. package/dist/src/mcp/license/key-source.js +58 -0
  13. package/dist/src/mcp/license/lemonsqueezy-verifier.js +207 -0
  14. package/dist/src/mcp/license/placeholder-verifier.js +10 -0
  15. package/dist/src/mcp/license/polar-ids.js +63 -0
  16. package/dist/src/mcp/license/polar-verifier.js +265 -0
  17. package/dist/src/mcp/license/product-ids.js +72 -0
  18. package/dist/src/mcp/license/state-store.js +91 -0
  19. package/dist/src/mcp/license/types.js +11 -0
  20. package/dist/src/mcp/logging.js +270 -0
  21. package/dist/src/mcp/product-info.js +48 -0
  22. package/dist/src/mcp/server.js +250 -0
  23. package/dist/src/mcp/setup.js +608 -0
  24. package/dist/src/mcp/start.cjs +95 -0
  25. package/dist/src/mcp/tool-definition.js +2 -0
  26. package/dist/src/mcp/tools.js +2004 -0
  27. package/dist/src/mcp/typography-rules.js +70 -0
  28. package/dist/src/transport/com.js +250 -0
  29. package/dist/src/transport/osascript.js +171 -0
  30. package/dist/src/transport/queue.js +19 -0
  31. package/dist/src/transport/script-bundle.js +92 -0
  32. package/dist/src/transport/transport.js +30 -0
  33. package/indesign/commands/10-app.js +6 -0
  34. package/indesign/commands/20-documents.js +513 -0
  35. package/indesign/commands/22-document-setup.js +118 -0
  36. package/indesign/commands/23-save-package.js +255 -0
  37. package/indesign/commands/25-export.js +379 -0
  38. package/indesign/commands/26-export-image.js +197 -0
  39. package/indesign/commands/27-textdefaults.js +151 -0
  40. package/indesign/commands/28-selection.js +174 -0
  41. package/indesign/commands/30-pages.js +1032 -0
  42. package/indesign/commands/31-view.js +210 -0
  43. package/indesign/commands/32-sections.js +203 -0
  44. package/indesign/commands/35-parents.js +428 -0
  45. package/indesign/commands/37-layout.js +760 -0
  46. package/indesign/commands/40-frames.js +836 -0
  47. package/indesign/commands/41-shapes.js +505 -0
  48. package/indesign/commands/42-groups.js +117 -0
  49. package/indesign/commands/43-layers.js +291 -0
  50. package/indesign/commands/44-effects.js +274 -0
  51. package/indesign/commands/45-frame-options.js +247 -0
  52. package/indesign/commands/47-anchored.js +287 -0
  53. package/indesign/commands/50-modify.js +781 -0
  54. package/indesign/commands/52-align.js +139 -0
  55. package/indesign/commands/55-fit.js +106 -0
  56. package/indesign/commands/60-images.js +771 -0
  57. package/indesign/commands/62-embed.js +120 -0
  58. package/indesign/commands/69-placeholders.js +127 -0
  59. package/indesign/commands/70-text.js +567 -0
  60. package/indesign/commands/71-outlines.js +92 -0
  61. package/indesign/commands/72-place-text.js +366 -0
  62. package/indesign/commands/74-stories.js +116 -0
  63. package/indesign/commands/75-tables.js +676 -0
  64. package/indesign/commands/76-text-variables.js +260 -0
  65. package/indesign/commands/77-story-options.js +86 -0
  66. package/indesign/commands/78-frame-lines.js +304 -0
  67. package/indesign/commands/79-check-typography.js +303 -0
  68. package/indesign/commands/80-styles.js +1620 -0
  69. package/indesign/commands/81-composition.js +355 -0
  70. package/indesign/commands/82-object-styles.js +263 -0
  71. package/indesign/commands/83-indents-tabs.js +237 -0
  72. package/indesign/commands/84-import-styles.js +142 -0
  73. package/indesign/commands/85-swatches.js +112 -0
  74. package/indesign/commands/86-gradients.js +185 -0
  75. package/indesign/commands/87-replace-swatch.js +180 -0
  76. package/indesign/commands/88-replace-font.js +217 -0
  77. package/indesign/interpreter.js +758 -0
  78. package/package.json +55 -6
  79. package/rules/typography-rules.json +31 -0
@@ -0,0 +1,139 @@
1
+ /* Wunschliste J2 Nr. 24 (Sitzung 8) – ausrichten und verteilen: align_objects. */
2
+
3
+ var IDC_ALIGN_OPTIONS = [
4
+ ['left', 'LEFT_EDGES'], ['horizontal_center', 'HORIZONTAL_CENTERS'], ['right', 'RIGHT_EDGES'],
5
+ ['top', 'TOP_EDGES'], ['vertical_center', 'VERTICAL_CENTERS'], ['bottom', 'BOTTOM_EDGES']
6
+ ];
7
+ var IDC_DISTRIBUTE_OPTIONS = [
8
+ ['left', 'LEFT_EDGES'], ['horizontal_center', 'HORIZONTAL_CENTERS'], ['right', 'RIGHT_EDGES'],
9
+ ['top', 'TOP_EDGES'], ['vertical_center', 'VERTICAL_CENTERS'], ['bottom', 'BOTTOM_EDGES'],
10
+ ['horizontal_space', 'HORIZONTAL_SPACE'], ['vertical_space', 'VERTICAL_SPACE']
11
+ ];
12
+ var IDC_ALIGN_BOUNDS = [
13
+ ['selection', 'ITEM_BOUNDS'], ['key_object', 'KEY_OBJECT'], ['margins', 'MARGIN_BOUNDS'],
14
+ ['page', 'PAGE_BOUNDS'], ['spread', 'SPREAD_BOUNDS']
15
+ ];
16
+
17
+ function idcAlignEnum(name) {
18
+ if (name === 'AlignOptions') { return typeof AlignOptions === 'undefined' ? null : AlignOptions; }
19
+ if (name === 'DistributeOptions') { return typeof DistributeOptions === 'undefined' ? null : DistributeOptions; }
20
+ if (name === 'AlignDistributeBounds') { return typeof AlignDistributeBounds === 'undefined' ? null : AlignDistributeBounds; }
21
+ return null;
22
+ }
23
+
24
+ /* Objekte fuer align/distribute einsammeln: gleiche Regeln wie group_frames. */
25
+ function idcAlignItems(doc, ids, what, minCount) {
26
+ var items = [], seen = {}, i, found, item, spread = null, other, bounds = [];
27
+ if (!IDC.isArray(ids) || ids.length < minCount) {
28
+ IDC.fail('invalid_argument', 'frame_ids must list at least ' + minCount + ' object ids.', { frame_ids: ids });
29
+ }
30
+ if (ids.length > 500) { IDC.fail('invalid_argument', 'frame_ids may list at most 500 objects.', { count: ids.length }); }
31
+ for (i = 0; i < ids.length; i++) {
32
+ if (typeof ids[i] !== 'number' || Math.floor(ids[i]) !== ids[i]) {
33
+ IDC.fail('invalid_argument', 'frame_ids must contain whole numbers.', { frame_ids: ids });
34
+ }
35
+ if (seen[ids[i]]) { IDC.fail('invalid_argument', 'frame_ids lists object ' + ids[i] + ' twice.', { frame_id: ids[i] }); }
36
+ seen[ids[i]] = true;
37
+ found = IDC.itemById(doc, ids[i], 'any');
38
+ if (found === null) { IDC.fail('not_found', 'No object with frame_id ' + ids[i] + ' in this document.', { frame_id: ids[i] }); }
39
+ item = found.item;
40
+ idcRejectGroupMember(item, ids[i], what);
41
+ idcRejectLocked(doc, item, ids[i], what);
42
+ other = IDC.spreadOfItem(item);
43
+ if (other === null) { IDC.fail('invalid_state', 'Object ' + ids[i] + ' is not on a spread.', { frame_id: ids[i] }); }
44
+ if (spread === null) { spread = other; }
45
+ else if (!idcSameObject(spread, other)) {
46
+ IDC.fail('invalid_state', 'All objects must lie on the same spread (Druckbogen); object ' + ids[i] + ' lies on another one.', { frame_id: ids[i] });
47
+ }
48
+ items.push(item);
49
+ }
50
+ return items;
51
+ }
52
+
53
+ function idcBoundsList(doc, items) {
54
+ var out = [], i;
55
+ for (i = 0; i < items.length; i++) {
56
+ out.push({ frame_id: Number(items[i].id), bounds_mm: idcItemBounds(doc, items[i]) });
57
+ }
58
+ return out;
59
+ }
60
+
61
+ IDC.register('align_objects', { needs_document: true, read_only: false, ruler: 'page' },
62
+ function (ctx) {
63
+ var args = ctx.args;
64
+ var doc = ctx.doc;
65
+ var mode = args.mode === undefined || args.mode === null ? 'align' : args.mode;
66
+ var relativeTo = args.relative_to === undefined || args.relative_to === null ? 'selection' : args.relative_to;
67
+ var items, keyItem = null, before, after, optionValue, boundsValue, spacing = null, changed = 0, i, j;
68
+ var optionsEnum, boundsEnum;
69
+
70
+ if (mode !== 'align' && mode !== 'distribute') {
71
+ IDC.fail('invalid_argument', 'mode must be align or distribute.', { mode: mode });
72
+ }
73
+ if (typeof args.edge !== 'string') { IDC.fail('invalid_argument', 'edge is required.', null); }
74
+ boundsEnum = idcAlignEnum('AlignDistributeBounds');
75
+ if (boundsEnum === null) { IDC.fail('invalid_state', 'This runtime has no AlignDistributeBounds enumeration.', null); }
76
+ boundsValue = idcEnumFor(IDC_ALIGN_BOUNDS, boundsEnum, relativeTo, 'relative_to');
77
+
78
+ items = idcAlignItems(doc, args.frame_ids, 'align_objects', mode === 'align' && relativeTo !== 'selection' && relativeTo !== 'key_object' ? 1 : 2);
79
+ if (relativeTo === 'key_object') {
80
+ if (args.key_frame_id === undefined || args.key_frame_id === null) {
81
+ IDC.fail('invalid_argument', 'relative_to key_object needs key_frame_id (one of frame_ids).', null);
82
+ }
83
+ for (i = 0; i < items.length; i++) { if (Number(items[i].id) === Number(args.key_frame_id)) { keyItem = items[i]; } }
84
+ if (keyItem === null) { IDC.fail('invalid_argument', 'key_frame_id must be one of frame_ids.', { key_frame_id: args.key_frame_id }); }
85
+ } else if (args.key_frame_id !== undefined && args.key_frame_id !== null) {
86
+ ctx.warn('key_frame_id is used with relative_to key_object only; ignored.');
87
+ }
88
+ if (args.spacing_mm !== undefined && args.spacing_mm !== null) {
89
+ if (mode !== 'distribute') { ctx.warn('spacing_mm applies to mode distribute only; ignored.'); }
90
+ else {
91
+ if (typeof args.spacing_mm !== 'number' || !isFinite(args.spacing_mm)) { IDC.fail('invalid_argument', 'spacing_mm must be a number (mm).', { spacing_mm: args.spacing_mm }); }
92
+ spacing = args.spacing_mm;
93
+ }
94
+ }
95
+
96
+ before = idcBoundsList(doc, items);
97
+ try {
98
+ if (mode === 'align') {
99
+ optionsEnum = idcAlignEnum('AlignOptions');
100
+ if (optionsEnum === null) { IDC.fail('invalid_state', 'This runtime has no AlignOptions enumeration.', null); }
101
+ optionValue = idcEnumFor(IDC_ALIGN_OPTIONS, optionsEnum, args.edge, 'edge');
102
+ if (keyItem !== null) { doc.align(items, optionValue, boundsValue, keyItem); }
103
+ else { doc.align(items, optionValue, boundsValue); }
104
+ } else {
105
+ optionsEnum = idcAlignEnum('DistributeOptions');
106
+ if (optionsEnum === null) { IDC.fail('invalid_state', 'This runtime has no DistributeOptions enumeration.', null); }
107
+ optionValue = idcEnumFor(IDC_DISTRIBUTE_OPTIONS, optionsEnum, args.edge, 'edge');
108
+ if (spacing !== null) {
109
+ if (keyItem !== null) { doc.distribute(items, optionValue, boundsValue, true, spacing, keyItem); }
110
+ else { doc.distribute(items, optionValue, boundsValue, true, spacing); }
111
+ } else if (keyItem !== null) {
112
+ doc.distribute(items, optionValue, boundsValue, false, 0, keyItem);
113
+ } else {
114
+ doc.distribute(items, optionValue, boundsValue);
115
+ }
116
+ }
117
+ } catch (e0) {
118
+ if (e0 && e0.isIdcError) { throw e0; }
119
+ IDC.fail('script_error', 'InDesign could not ' + mode + ' the objects: ' + String(e0.message ? e0.message : e0), { frame_ids: args.frame_ids, edge: args.edge });
120
+ }
121
+ after = idcBoundsList(doc, items);
122
+ for (i = 0; i < after.length; i++) {
123
+ if (IDC.stringify(after[i].bounds_mm) !== IDC.stringify(before[i].bounds_mm)) { changed += 1; }
124
+ }
125
+ j = [];
126
+ for (i = 0; i < items.length; i++) { j.push(Number(items[i].id)); }
127
+ if (changed === 0) { ctx.warn('No object moved – they were already ' + (mode === 'align' ? 'aligned' : 'distributed') + ' that way.'); }
128
+ ctx.changes = { modified_frame_ids: j };
129
+ return {
130
+ mode: mode,
131
+ edge: args.edge,
132
+ relative_to: relativeTo,
133
+ key_frame_id: keyItem === null ? null : Number(keyItem.id),
134
+ spacing_mm: spacing,
135
+ objects: after,
136
+ before: before,
137
+ moved_count: changed
138
+ };
139
+ });
@@ -0,0 +1,106 @@
1
+ /* Wunschliste J2 Nr. 16 (Sitzung 7) – Einpassen: fit_frame. */
2
+
3
+ function idcFitModeFor(name) {
4
+ if (typeof FitOptions === 'undefined') { return null; }
5
+ if (name === 'frame_to_content') { return FitOptions.FRAME_TO_CONTENT; }
6
+ if (name === 'content_to_frame') { return FitOptions.CONTENT_TO_FRAME; }
7
+ if (name === 'fit_proportionally') { return FitOptions.PROPORTIONALLY; }
8
+ if (name === 'fill_proportionally') { return FitOptions.FILL_PROPORTIONALLY; }
9
+ if (name === 'center_content') { return FitOptions.CENTER_CONTENT; }
10
+ return null;
11
+ }
12
+
13
+ IDC.register('fit_frame', { needs_document: true, read_only: false, ruler: 'page' },
14
+ function (ctx) {
15
+ var args = ctx.args;
16
+ var doc = ctx.doc;
17
+ var found = idcFrameArg(doc, args, 'frame_id');
18
+ var item = found.item;
19
+ var mode = args.mode;
20
+ var type = IDC.itemType(item);
21
+ var option, page, before, after, graphics, entry = null, overset = null, minPpi;
22
+ var keepWidth = args.keep_width === true;
23
+
24
+ if (typeof mode !== 'string' || (idcFitModeFor(mode) === null && typeof FitOptions !== 'undefined')) {
25
+ IDC.fail('invalid_argument', 'mode must be frame_to_content, content_to_frame, fit_proportionally, fill_proportionally or center_content.', { mode: mode });
26
+ }
27
+ if (type === 'group' || type === 'line') {
28
+ IDC.fail('invalid_state', 'Object ' + args.frame_id + ' is a ' + type + '; fit_frame works on text and graphic frames.', { frame_id: args.frame_id, type: type });
29
+ }
30
+ if (type === 'text' && mode !== 'frame_to_content') {
31
+ IDC.fail('invalid_state', 'Text frame ' + args.frame_id + ': only mode frame_to_content applies to text (the frame shrinks or grows to its text).',
32
+ { frame_id: args.frame_id, mode: mode });
33
+ }
34
+ if (type !== 'text') {
35
+ graphics = idcGraphicsOf(item);
36
+ if (graphics.length === 0) {
37
+ IDC.fail('invalid_state', 'Frame ' + args.frame_id + ' holds no graphic; place one first (place_image).', { frame_id: args.frame_id });
38
+ }
39
+ }
40
+ idcRejectGroupMember(item, args.frame_id, 'fit_frame');
41
+
42
+ page = idcPageOfItem(doc, item);
43
+ before = IDC.boundsOnPage(doc, item, page);
44
+ var recBeforeFit = idcRecomposeBefore(doc, item);
45
+ option = idcFitModeFor(mode);
46
+ try {
47
+ if (type === 'text' && keepWidth) {
48
+ /*
49
+ * Nur die Hoehe anpassen: InDesigns fit(FRAME_TO_CONTENT) zieht bei
50
+ * Text auch die Breite auf die laengste Zeile (Live-Fund 05.09.2026).
51
+ * Der Weg ueber die automatische Groesse (nur Hoehe, Bezug oben links)
52
+ * haelt die Breite; danach wieder aus, damit der Rahmen fest bleibt.
53
+ */
54
+ var tfp = item.textFramePreferences;
55
+ var prevType = tfp.autoSizingType;
56
+ var prevRef = tfp.autoSizingReferencePoint;
57
+ tfp.autoSizingReferencePoint = AutoSizingReferenceEnum.TOP_LEFT_POINT;
58
+ tfp.autoSizingType = AutoSizingTypeEnum.HEIGHT_ONLY;
59
+ tfp.autoSizingType = prevType;
60
+ tfp.autoSizingReferencePoint = prevRef;
61
+ } else {
62
+ item.fit(option);
63
+ }
64
+ } catch (e) {
65
+ IDC.fail('script_error', 'InDesign could not fit object ' + args.frame_id + ' (' + mode + '): ' + String(e.message ? e.message : e),
66
+ { frame_id: args.frame_id, mode: mode });
67
+ }
68
+ var recFit = idcRecomposeAfter(ctx, doc, recBeforeFit);
69
+ page = idcPageOfItem(doc, item);
70
+ after = IDC.boundsOnPage(doc, item, page);
71
+
72
+ if (type === 'text') {
73
+ try { overset = item.overflows === true; } catch (e1) { overset = null; }
74
+ if (overset === true) { ctx.warn('The text frame still overflows after fitting.'); }
75
+ } else {
76
+ graphics = idcGraphicsOf(item);
77
+ entry = idcDescribeGraphic(doc, item, graphics[0], page);
78
+ minPpi = idcMinPpi(args);
79
+ if (entry.effective_ppi !== null && entry.effective_ppi < minPpi && !entry.is_pdf) {
80
+ ctx.warn('Effective resolution is ' + entry.effective_ppi + ' ppi after fitting – below ' + minPpi + ' ppi (min_ppi).');
81
+ }
82
+ }
83
+
84
+ var changed = Math.abs(before.x - after.x) > 0.0005 || Math.abs(before.y - after.y) > 0.0005
85
+ || Math.abs(before.width - after.width) > 0.0005 || Math.abs(before.height - after.height) > 0.0005;
86
+ ctx.changes = { modified_frame_ids: [Number(item.id)] };
87
+ return {
88
+ frame_id: Number(item.id),
89
+ type: type,
90
+ mode: mode,
91
+ keep_width: type === 'text' ? keepWidth : null,
92
+ frame_bounds_before_mm: before,
93
+ frame_bounds_mm: after,
94
+ coordinate_space: page === null ? 'spread' : 'page',
95
+ frame_changed: changed,
96
+ recomposed: recFit.recomposed,
97
+ overset_stories_before: recFit.overset_stories_before,
98
+ overset_stories_after: recFit.overset_stories_after,
99
+ overset_changed: recFit.overset_changed,
100
+ graphic_bounds_mm: entry === null ? null : entry.graphic_bounds,
101
+ fits_frame: entry === null ? null : idcCoversFrame(after, entry.graphic_bounds),
102
+ effective_ppi: entry === null ? null : entry.effective_ppi,
103
+ overset: overset,
104
+ page_id: page === null ? null : Number(page.id)
105
+ };
106
+ });