feat: F4.8a the documentation items in model and file, measured against Java's

New oracle DocuRun on Java's JDocuElement. Italic is kept (the model knew
only bold), an item keeps its file's size and font size (Swift's 32 x 24
and 8-72 changed Java's files), an item without a colour is Java's light
grey. Java's new items, colour lists, font sizes and styles, the drag's
smallest sizes and Java's stacking; document commands for the editor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 10:42:21 +00:00
co-authored by Claude Opus 5.5
parent 9252b942c4
commit 56cdb4926e
18 changed files with 1889 additions and 57 deletions
+4 -3
View File
@@ -57,8 +57,8 @@
// interface, as Java's own setters (setStandardGateway, setDNSServer) do:
// Java reads them from the first interface only (getStandardGateway,
// getDNSServer), and the model keeps no others;
// - a documentation item always has a text and a font, bold or plain: where
// Java has none, the empty text and Dialog 12 the model gives it;
// - a documentation item always has a text, a font and a colour: where
// Java has none, the empty text, Dialog 12 and the light grey Java shows;
// - a switch's SSID the file lacked (Java rolls one) is the one the model
// derives from the node's id;
// - files in the model's order (directories first, then by name) and of the
@@ -105,6 +105,7 @@ import {
type ManualRoute,
type RemoteLinkConfiguration,
type SwitchConfiguration,
documentationFontStyle,
type DocumentationItem,
type HostLabelPolicy,
type HostWirelessConfiguration,
@@ -554,6 +555,6 @@ function exportDocumentationItem(item: DocumentationItem): FlsDocumentationItem
width: Math.round(item.frame.width),
height: Math.round(item.frame.height),
color: [channel(item.color.red), channel(item.color.green), channel(item.color.blue), channel(item.color.alpha)],
font: { name: item.fontName, style: item.isBold ? 1 : 0, size: item.fontSize },
font: { name: item.fontName, style: documentationFontStyle(item), size: item.fontSize },
};
}
+4 -3
View File
@@ -65,8 +65,7 @@ import {
VirtualFileSystem,
VirtualFileSystemError,
topologyNode,
DOCUMENTATION_BLACK,
DOCUMENTATION_PALE_YELLOW,
DOCUMENTATION_LIGHT_GRAY,
type DeviceConfiguration,
type DhcpClientConfiguration,
type DhcpServerConfiguration,
@@ -770,7 +769,8 @@ function importDocumentationItem(
const seed = `java-doc|${order}|${item.type}|${item.x}|${item.y}|${item.width}|${item.height}|${text}`;
let color;
if (item.color === null) {
color = kind === 'text' ? DOCUMENTATION_BLACK : DOCUMENTATION_PALE_YELLOW;
// Java shows it light grey, either kind (JDocuElement.setColor(null)).
color = DOCUMENTATION_LIGHT_GRAY;
warnings.push(`documentation item ${order + 1} without a color, given the default`);
} else {
const [red, green, blue, alpha] = item.color;
@@ -785,6 +785,7 @@ function importDocumentationItem(
fontName: item.font?.name ?? 'Dialog',
fontSize: item.font?.size ?? 12,
isBold: ((item.font?.style ?? 0) & 1) === 1,
isItalic: ((item.font?.style ?? 0) & 2) === 2,
order,
});
}
+34 -4
View File
@@ -14,7 +14,6 @@ import { fileURLToPath } from 'node:url';
import {
defaultSwitchConfiguration,
dhcpServerConfiguration,
DOCUMENTATION_MINIMUM_SIZE,
firewallConfiguration,
firewallRule,
stableGeneratedMacAddress,
@@ -104,8 +103,8 @@ function topologyOf(view: JavaFile) {
* - generatedMac: a card whose MAC the file lacked (Java rolls a new one at
* each load) has the one the simulation uses, derived from its port id;
* - documentation: the items in the model's render order (rectangles below
* text), a missing text empty, a missing font Dialog 12, and at least the
* editor's smallest size (DOCUMENTATION_MINIMUM_SIZE);
* text), a missing text empty, a missing font Dialog 12, a missing colour
* the light grey Java shows for it;
* - switchSsid: a switch's SSID the file lacked (Java rolls one) is the one
* the model derives from the node's id;
* - modemRoles: the model keeps a pair of modems, not which one serves: the
@@ -212,8 +211,9 @@ const DEPARTURES = {
return {
...item,
text: item.text ?? '',
bounds: [x, y, Math.max(width!, DOCUMENTATION_MINIMUM_SIZE.width), Math.max(height!, DOCUMENTATION_MINIMUM_SIZE.height)],
bounds: [x, y, width, height],
font: item.font ?? ['Dialog', 12, 0],
color: item.color ?? [192, 192, 192, 255],
};
});
return { ...view, documentation: sortedDocumentation(items) };
@@ -677,6 +677,7 @@ const SYNTHETIC: ProjectToExport = {
fontName: 'Dialog',
fontSize: 12,
isBold: false,
isItalic: false,
order: 0,
},
{
@@ -688,8 +689,34 @@ const SYNTHETIC: ProjectToExport = {
fontName: 'SansSerif',
fontSize: 16,
isBold: true,
isItalic: false,
order: 1,
},
// Italic, bold and italic, smaller than Swift's smallest size: kept as they are.
{
id: 'd3',
kind: 'text',
frame: { x: 400, y: 10, width: 15, height: 10 },
text: 'kursiv',
color: { red: 0.31, green: 0.51, blue: 0.74, alpha: 1 },
fontName: 'Dialog',
fontSize: 6,
isBold: false,
isItalic: true,
order: 2,
},
{
id: 'd4',
kind: 'text',
frame: { x: 400, y: 40, width: 88, height: 20 },
text: 'beides',
color: { red: 0, green: 0, blue: 0, alpha: 1 },
fontName: 'Serif',
fontSize: 24,
isBold: true,
isItalic: true,
order: 3,
},
],
};
@@ -933,6 +960,9 @@ describe('a model beyond the corpus, as Java loads it', () => {
documentation: [
{ type: 1, text: '', bounds: [5, 6, 300, 200], color: [255, 128, 0, 128], font: ['Dialog', 12, 0] },
{ type: 2, text: 'Netz A\nzweite Zeile', bounds: [40, 51, 120, 30], color: [0, 0, 255, 255], font: ['SansSerif', 16, 1] },
// Java's italic (2) and bold italic (3), and sizes below Swift's smallest, as the model keeps them.
{ type: 2, text: 'kursiv', bounds: [400, 10, 15, 10], color: [79, 130, 189, 255], font: ['Dialog', 6, 2] },
{ type: 2, text: 'beides', bounds: [400, 40, 88, 20], color: [0, 0, 0, 255], font: ['Serif', 24, 3] },
],
});
});
+62 -20
View File
@@ -604,7 +604,7 @@
508,
390,
88,
24
20
],
"color": [
0,
@@ -646,7 +646,7 @@
453,
124,
100,
24
20
],
"color": [
0,
@@ -667,7 +667,7 @@
308,
123,
88,
24
20
],
"color": [
0,
@@ -688,7 +688,7 @@
631,
391,
88,
24
20
],
"color": [
0,
@@ -808,7 +808,7 @@
]
}
],
"sha256": "edad61949744c17c11d75b6abd180f9916c0f06d643c332209c301778f7ab753"
"sha256": "4c8042374d8f8db186bba920831d9cff9b7a0009c9d5bab094de920954b1fc98"
},
"ipad-fixtures/dns_server.fls": {
"success": true,
@@ -4403,7 +4403,7 @@
570,
583,
88,
24
20
],
"color": [
0,
@@ -4445,7 +4445,7 @@
209,
907,
88,
24
20
],
"color": [
0,
@@ -4550,7 +4550,7 @@
458,
383,
88,
24
20
],
"color": [
0,
@@ -4571,7 +4571,7 @@
298,
268,
88,
24
20
],
"color": [
0,
@@ -4586,7 +4586,7 @@
]
}
],
"sha256": "5bf3c778a721c2bf41c9203d28f07d3052fa0257f80dcc05911126bc336ab066"
"sha256": "d31a32691f4b82cb683beda090b810671e269fe82a45b5b0810654998d1d8b7b"
},
"java-examples/Internet_Komplett_mit_eMail_Webserver_Intranet_Portforwarding_Firewall_DHCP_DE.fls": {
"success": true,
@@ -7192,7 +7192,7 @@
570,
583,
88,
24
20
],
"color": [
0,
@@ -7234,7 +7234,7 @@
255,
897,
88,
24
20
],
"color": [
0,
@@ -7318,7 +7318,7 @@
440,
907,
108,
24
23
],
"color": [
0,
@@ -7333,7 +7333,7 @@
]
}
],
"sha256": "e56c3b8aec2610d3dedcf7f2c1b3d715aa7bb0eedeb5298ea21c5fd6ff0aba8d"
"sha256": "fa1b339614ba08b53a678ac1242cd26d03b36ec224f4e9a42fba20df050bd31f"
},
"java-examples/Public_and_Private_Networks_2_EN.fls": {
"success": true,
@@ -7940,7 +7940,7 @@
508,
390,
88,
24
20
],
"color": [
0,
@@ -7982,7 +7982,7 @@
453,
124,
100,
24
20
],
"color": [
0,
@@ -8003,7 +8003,7 @@
308,
123,
88,
24
20
],
"color": [
0,
@@ -8024,7 +8024,7 @@
631,
391,
88,
24
20
],
"color": [
0,
@@ -8144,7 +8144,7 @@
]
}
],
"sha256": "edad61949744c17c11d75b6abd180f9916c0f06d643c332209c301778f7ab753"
"sha256": "4c8042374d8f8db186bba920831d9cff9b7a0009c9d5bab094de920954b1fc98"
},
"java-examples/anwendung_komplett.fls": {
"success": true,
@@ -19681,8 +19681,50 @@
16,
1
]
},
{
"type": 2,
"text": "kursiv",
"bounds": [
400,
10,
15,
10
],
"color": [
79,
130,
189,
255
],
"font": [
"Dialog",
6,
2
]
},
{
"type": 2,
"text": "beides",
"bounds": [
400,
40,
88,
20
],
"color": [
0,
0,
0,
255
],
"font": [
"Serif",
24,
3
]
}
],
"sha256": "7e1837d138d433f9721d2852de79f582ccb1e0454fcd100e30f37ab9e324ca58"
"sha256": "dd6692f81ff1eca0214a1c85bce9dbccf99c62b41a84b3a01213f562ffdef483"
}
}
+12 -2
View File
@@ -1282,18 +1282,28 @@ describe('importProject rules', () => {
{ ...item, type: 2, color: null },
{ ...item, type: 1, width: 0, color: [1, 2, 3, 255] },
{ ...item, type: 3, color: [1, 2, 3, 255] },
{ ...item, type: 1, text: null, color: null },
{ ...item, type: 2, width: 15, height: 10, color: [1, 2, 3, 255], font: { name: 'Serif', style: 3, size: 6 } },
{ ...item, type: 2, color: [1, 2, 3, 255], font: { name: 'Dialog', style: 2, size: 18 } },
],
}),
counter(),
);
expect(project.documentationItems.map((doc) => [doc.kind, doc.text, doc.color, doc.fontName, doc.fontSize])).toEqual([
['text', 'Hallo', { red: 0, green: 0, blue: 0, alpha: 1 }, 'Dialog', 12],
// Without a colour, light grey, as Java shows it (JDocuElement.setColor(null)), either kind; italic kept; a small size and font size kept.
const grey = { red: 192 / 255, green: 192 / 255, blue: 192 / 255, alpha: 1 };
const rgb = { red: 1 / 255, green: 2 / 255, blue: 3 / 255, alpha: 1 };
expect(project.documentationItems.map((doc) => [doc.kind, doc.text, doc.color, doc.fontName, doc.fontSize, doc.isBold, doc.isItalic, doc.frame.width, doc.frame.height])).toEqual([
['rectangle', '', grey, 'Dialog', 12, false, false, 100, 30],
['text', 'Hallo', grey, 'Dialog', 12, false, false, 100, 30],
['text', 'Hallo', rgb, 'Serif', 6, true, true, 15, 10],
['text', 'Hallo', rgb, 'Dialog', 18, false, true, 100, 30],
]);
expect(project.warnings).toEqual([
'documentation item 1 without a color, given the default',
'documentation item without size, left out',
'documentation item of type 3, left out (known: RECT = 1, TEXT = 2)',
'documentation item 2 without a color, given the default',
]);
});
});