feat(fls): a project's own applications through the editor model

The model carries the captured beans of a project's own applications
(ownApplicationsByNodeId); the export writes them again on the system
software of their node, and their classes go with the archive's other
entries. Checked by Java: from the exported files FILIUS loads
Accumulator and Broadcast as from the original; the export test no longer
leaves own applications out, and a probe that drops them is caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 09:44:39 +00:00
co-authored by Claude Opus 5.5
parent 3548652687
commit c8f2e9e225
6 changed files with 44 additions and 12 deletions
+12 -3
View File
@@ -30,7 +30,8 @@
// model keeps it), the echo server's port, the generic client's target, the
// peer count, the personal firewall. A DNS server's records are in
// /dns/hosts, one of the files, and it forwards to the host's DNS server as
// Java's does.
// Java's does. A project's own applications are written as their beans,
// as the file had them; their classes go with the archive's other entries.
//
// E-mail: the server's domain and accounts with their mailboxes, the client's
// folders and address book, as Java's beans. The account files are written
@@ -114,7 +115,7 @@ import {
import { writeFlsArchive } from './archive.js';
import { EMAIL_CLIENT_FILE, EMAIL_SERVER_FILE, type JavaAddressEntry, type JavaContact, type JavaEmail } from './javaEmail.js';
import { PROGRAM_OF_CLASS } from './importProject.js';
import type { FlsApplicationClass, FlsDhcpServer, FlsFileTree, FlsFirewall } from './systemSoftware.js';
import type { FlsApplicationClass, FlsDhcpServer, FlsFileTree, FlsFirewall, FlsOwnApplication } from './systemSoftware.js';
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNodeClass } from './topology.js';
import { writeTopologyXml, type ApplicationToWrite, type NodeToWrite, type SystemToWrite, type TopologyToWrite } from './topologyWriter.js';
@@ -145,6 +146,8 @@ export interface ProjectToExport {
readonly documentationItems: readonly DocumentationItem[];
/** The archive's other entries (the project's own applications), written unchanged. */
readonly archiveEntries?: ReadonlyMap<string, Uint8Array>;
/** A project's own applications on a PC or notebook, written as their beans. */
readonly ownApplicationsByNodeId?: ReadonlyMap<Id, readonly FlsOwnApplication[]>;
}
export interface ExportedTopology {
@@ -286,7 +289,13 @@ function exportSystem(node: TopologyNode, project: ProjectToExport, servingModem
const server = project.installedPrograms.get(id)?.has('emailServer') === true ? project.emailServerConfigurations.get(id) : undefined;
if (client?.account != null) putFile(root, EMAIL_CLIENT_FILE, 'text/txt', clientAccountFile(client, warn));
if (server !== undefined) putFile(root, EMAIL_SERVER_FILE, 'txt', serverAccountsFile(server, warn));
return { ...system, ssid: ssid === '' ? null : ssid, fileSystem: root, applications: exportPrograms(id, project) };
return {
...system,
ssid: ssid === '' ? null : ssid,
fileSystem: root,
applications: exportPrograms(id, project),
ownApplications: [...(project.ownApplicationsByNodeId?.get(id) ?? [])],
};
}
case 'router':
return {
+11 -1
View File
@@ -101,7 +101,7 @@ import { readFlsArchive } from './archive.js';
import { dnsRecordsOf, javaHostsFileContent, readDnsHosts } from './dnsHosts.js';
import { decodeJavaBeans } from './javabeans.js';
import { emailClientConfiguration, emailServerConfiguration } from './importEmail.js';
import type { FlsApplicationClass, FlsFileTree, FlsFirewall } from './systemSoftware.js';
import type { FlsApplicationClass, FlsFileTree, FlsFirewall, FlsOwnApplication } from './systemSoftware.js';
import { readTopology, type FlsDocumentationItem, type FlsInterface, type FlsNode, type FlsNodeClass, type FlsTopology } from './topology.js';
export interface ImportedProject {
@@ -140,6 +140,12 @@ export interface ImportedProject {
* they cannot run here, but must not be lost.
*/
archiveEntries: ReadonlyMap<string, Uint8Array>;
/**
* A project's own applications on a PC or notebook, as their beans
* (beanCapture.ts): they cannot run here, but are written again as the
* file had them. Their classes are among the archive's entries.
*/
ownApplicationsByNodeId: Map<Id, FlsOwnApplication[]>;
/** The topology's warnings, then this step's. */
warnings: string[];
}
@@ -188,6 +194,7 @@ export function importProject(
echoServerConfigurations: new Map(),
simpleClientConfigurations: new Map(),
};
const ownApplicationsByNodeId = new Map<Id, FlsOwnApplication[]>();
const nodes = topology.nodes.map((source) => {
const node = importNode(source, newId, warnings);
registerConfigurations(source, node, deviceConfigurations, interfaceConfigurations);
@@ -196,6 +203,8 @@ export function importProject(
if (node.kind === 'pc' || node.kind === 'notebook') {
system.virtualFileSystems.set(node.id, importFileSystem(source.system.fileSystem, node.displayName, warnings));
registerPrograms(source, node, system, warnings);
const own = source.system.ownApplications ?? [];
if (own.length > 0) ownApplicationsByNodeId.set(node.id, own);
}
return node;
});
@@ -249,6 +258,7 @@ export function importProject(
...system,
documentationItems: inDeterministicRenderOrder(documentationItems),
archiveEntries,
ownApplicationsByNodeId,
warnings,
};
}