feat(fls): read and write a project's own applications as their beans
A project's own applications (classes under projekt/anwendungen, installed on a host) are no longer left out. The decoder now keeps the Java type of every primitive — at setters, constructor and call arguments, also through shared ids like Integer0 — and which properties an object's own getter made. beanCapture.ts turns a decoded bean back into what the writer writes, with the node's system software as a mark the writer replaces by the system software it writes; what the format cannot say is refused, not guessed (an unresolved value, a Field, a factory-made object, an object a getter reaches elsewhere in the file). The reader keeps own applications as captured beans; the corpus no longer warns. The capture first took a setter with another object's getter result for an own getter; the round-trip test found it. The Java oracle did not show whether an application runs on its node's system software, so a mutation writing the mark instead survived; it now reports onItsSystem (true for all 192 applications of the corpus). Checked by Java: from the files written again, FILIUS loads Accumulator and Broadcast installed, switched on and on their node's system software, as in the original. The round-trip test covers every primitive, null, a class, an array, shared objects, getter chains, constructed elements, map reads and static constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,9 @@ import {
|
||||
type JavaEmailAccount,
|
||||
} from '../src/index.js';
|
||||
import { EXPECTED_WARNINGS } from './expectedWarnings.js';
|
||||
import { hasOwnApplications, OWN_APPLICATION_FILES, withoutOwnApplications } from './ownApplications.js';
|
||||
import { SYSTEM_SOFTWARE_CLASS } from '../src/beanCapture.js';
|
||||
import type { BeanValue } from '../src/javaBeansWriter.js';
|
||||
import { hasOwnApplications, OWN_APPLICATION_FILES, withOwnApplicationsByClass } from './ownApplications.js';
|
||||
import { javaEmail, javaEmailAccount } from './javaEmailNames.js';
|
||||
|
||||
const corpusRoot = join(dirname(fileURLToPath(import.meta.url)), '../../../corpus');
|
||||
@@ -69,12 +71,18 @@ function javaFileTree(tree: FlsFileTree): unknown {
|
||||
}
|
||||
|
||||
/** FlsOracle.applications' shape: Java's property names, sorted by key. */
|
||||
function isSystemSoftwareMark(value: BeanValue): boolean {
|
||||
return value !== null && typeof value === 'object' && value.kind === 'object' && value.className === SYSTEM_SOFTWARE_CLASS;
|
||||
}
|
||||
|
||||
function javaApplications(applications: FlsApplication[]): unknown[] {
|
||||
return [...applications]
|
||||
.sort((lhs, rhs) => ((lhs.key ?? '') < (rhs.key ?? '') ? -1 : 1))
|
||||
.map((application) => ({
|
||||
key: application.key,
|
||||
class: application.javaClass,
|
||||
// The reader's applications are its node's: each file gives them its system software.
|
||||
onItsSystem: true,
|
||||
...(application.isActive === undefined ? {} : { aktiv: application.isActive, port: application.port }),
|
||||
...(application.targetPort === undefined
|
||||
? {}
|
||||
@@ -178,7 +186,21 @@ function asJavaView(topology: FlsTopology, javaBounds: (number[] | null)[]) {
|
||||
...(node.system.modem === undefined ? {} : { modem: javaModem(node.system.modem) }),
|
||||
...(node.system.fileSystem === undefined ? {} : { fileSystem: javaFileTree(node.system.fileSystem) }),
|
||||
...('templateFiles' in node.system ? { templateFiles: undefined } : {}),
|
||||
...(node.system.applications === undefined ? {} : { applications: javaApplications(node.system.applications) }),
|
||||
...(node.system.applications === undefined
|
||||
? {}
|
||||
: {
|
||||
applications: [
|
||||
...(javaApplications(node.system.applications) as { key: string | null }[]),
|
||||
...(node.system.ownApplications ?? []).map((application) => ({
|
||||
key: application.key,
|
||||
class: application.javaClass,
|
||||
onItsSystem: application.bean.statements?.some(
|
||||
(statement) => 'set' in statement && statement.set === 'systemSoftware' && isSystemSoftwareMark(statement.value),
|
||||
),
|
||||
})),
|
||||
].sort((lhs, rhs) => ((lhs.key ?? '') < (rhs.key ?? '') ? -1 : 1)),
|
||||
}),
|
||||
...('ownApplications' in node.system ? { ownApplications: undefined } : {}),
|
||||
...(node.system.firewall === undefined
|
||||
? {}
|
||||
: {
|
||||
@@ -252,7 +274,7 @@ describe('corpus: the topology as Java loads it', () => {
|
||||
const expected = javaView[name] as { nodes: { bounds: number[] | null }[] };
|
||||
|
||||
expect(asJavaView(topology, expected.nodes.map((node) => node.bounds))).toEqual(
|
||||
withoutTemplateFiles(withoutOwnApplications(expected), topology),
|
||||
withoutTemplateFiles(withOwnApplicationsByClass(expected), topology),
|
||||
);
|
||||
expect(topology.warnings).toEqual(EXPECTED_WARNINGS[name] ?? []);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user