|
|
|
@ -1,15 +1,13 @@
|
|
|
|
// @vitest-environment jsdom
|
|
|
|
// @vitest-environment jsdom
|
|
|
|
|
|
|
|
|
|
|
|
import { existsSync } from 'node:fs';
|
|
|
|
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
|
|
|
|
|
|
import { dirname, join } from 'node:path';
|
|
|
|
|
|
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
|
|
|
|
|
|
|
|
import { createActiveApp, type ActiveApp } from '$active-app';
|
|
|
|
import { createActiveApp, type ActiveApp } from '$active-app';
|
|
|
|
import { createActiveDom } from '$adom';
|
|
|
|
import { createActiveDom } from '$adom';
|
|
|
|
import {
|
|
|
|
import { createActivePrefs, createActivePrefsDomProjection, standardPrefsDimensions } from '$prefs';
|
|
|
|
createActivePrefs,
|
|
|
|
|
|
|
|
createActivePrefsDomProjection,
|
|
|
|
|
|
|
|
standardPrefsDimensions
|
|
|
|
|
|
|
|
} from '$prefs';
|
|
|
|
|
|
|
|
import type { LangNode } from '$libs/langs';
|
|
|
|
import type { LangNode } from '$libs/langs';
|
|
|
|
import { state } from '$libs/reactive';
|
|
|
|
import { state } from '$libs/reactive';
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
@ -43,6 +41,9 @@ const prefsProjectionSchema = standardPrefsDimensions({
|
|
|
|
currency: 'EUR'
|
|
|
|
currency: 'EUR'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
|
|
|
|
|
|
const REPO_ROOT = join(HERE, '..', '..');
|
|
|
|
|
|
|
|
const SOURCE_EXTENSIONS = ['.ts', '.svelte'] as const;
|
|
|
|
|
|
|
|
|
|
|
|
function preferencesHarness() {
|
|
|
|
function preferencesHarness() {
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
@ -53,6 +54,23 @@ function preferencesHarness() {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function listSourceFiles(root: string): string[] {
|
|
|
|
|
|
|
|
const stat = statSync(root);
|
|
|
|
|
|
|
|
if (stat.isFile()) {
|
|
|
|
|
|
|
|
return SOURCE_EXTENSIONS.some((ext) => root.endsWith(ext)) ? [root] : [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return readdirSync(root)
|
|
|
|
|
|
|
|
.flatMap((entry) => listSourceFiles(join(root, entry)))
|
|
|
|
|
|
|
|
.filter(
|
|
|
|
|
|
|
|
(path) => !path.endsWith('.test.ts') && !path.includes(`${join('components', 'icon', 'lib')}`)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function grepSources(root: string, pattern: RegExp): string[] {
|
|
|
|
|
|
|
|
return listSourceFiles(root).filter((file) => pattern.test(readFileSync(file, 'utf8')));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
describe('UIX layer contracts', () => {
|
|
|
|
describe('UIX layer contracts', () => {
|
|
|
|
it('pins ActiveUix public service names and rejects legacy aliases', () => {
|
|
|
|
it('pins ActiveUix public service names and rejects legacy aliases', () => {
|
|
|
|
const uix = createActiveUix({ langs: minimalLang });
|
|
|
|
const uix = createActiveUix({ langs: minimalLang });
|
|
|
|
@ -109,6 +127,16 @@ describe('UIX layer contracts', () => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('guards ActiveUix as composition root, not Soma/Eidos bootstrapper', () => {
|
|
|
|
|
|
|
|
const source = readFileSync(join(HERE, 'active-uix', 'active-uix.svelte.ts'), 'utf8');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(source).not.toMatch(/from ['"].*\/soma/);
|
|
|
|
|
|
|
|
expect(source).not.toMatch(/from ['"].*\/eidos/);
|
|
|
|
|
|
|
|
expect(source).not.toMatch(/\bSoma\.create\(/);
|
|
|
|
|
|
|
|
expect(source).not.toMatch(/\bActiveEidos\.create\(/);
|
|
|
|
|
|
|
|
expect(source).not.toMatch(/\bEidos\.create\(/);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('prefs DOM projection owns only cross-modal attrs', () => {
|
|
|
|
it('prefs DOM projection owns only cross-modal attrs', () => {
|
|
|
|
expect(UIX_LAYER_CONTRACTS.prefsDomProjection.implementation).toBe(
|
|
|
|
expect(UIX_LAYER_CONTRACTS.prefsDomProjection.implementation).toBe(
|
|
|
|
'$prefs.createActivePrefsDomProjection'
|
|
|
|
'$prefs.createActivePrefsDomProjection'
|
|
|
|
@ -169,6 +197,14 @@ describe('UIX layer contracts', () => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('guards Soma components from legacy runtime registration APIs', () => {
|
|
|
|
|
|
|
|
const violations = grepSources(
|
|
|
|
|
|
|
|
join(HERE, 'soma', 'components'),
|
|
|
|
|
|
|
|
/registerContract\(|registerPart\(/
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(violations).toEqual([]);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('events/sema uses events as service name and requires dom or projector for visual projection', () => {
|
|
|
|
it('events/sema uses events as service name and requires dom or projector for visual projection', () => {
|
|
|
|
const factory = defineEngineSemantic({ visual: false });
|
|
|
|
const factory = defineEngineSemantic({ visual: false });
|
|
|
|
expect(factory.name).toBe(UIX_LAYER_CONTRACTS.events.publicServiceName);
|
|
|
|
expect(factory.name).toBe(UIX_LAYER_CONTRACTS.events.publicServiceName);
|
|
|
|
@ -207,6 +243,14 @@ describe('UIX layer contracts', () => {
|
|
|
|
eidos.dispose();
|
|
|
|
eidos.dispose();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('guards UIX docs shell from writing visual prefs through ActivePrefs', () => {
|
|
|
|
|
|
|
|
const violations = grepSources(
|
|
|
|
|
|
|
|
join(REPO_ROOT, 'web', 'routes', 'uix'),
|
|
|
|
|
|
|
|
/prefs\.theme|setIntent\(['"]theme['"]/
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
expect(violations).toEqual([]);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('Morfo owns translations declaratively and only registers them into a target', () => {
|
|
|
|
it('Morfo owns translations declaratively and only registers them into a target', () => {
|
|
|
|
_resetMorfoRegistryForTesting();
|
|
|
|
_resetMorfoRegistryForTesting();
|
|
|
|
const applied: Array<{ namespace: string; module: LangNode }> = [];
|
|
|
|
const applied: Array<{ namespace: string; module: LangNode }> = [];
|
|
|
|
|