@open-mercato/cli 0.6.8-develop.6931.1.4a1e1c786b → 0.6.8-develop.6940.1.177ea30c6e
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.
- package/.turbo/turbo-build.log +65 -1
- package/build.mjs +57 -7
- package/dist/agentic/guides/backend-ui.md +7 -1
- package/dist/agentic/guides/module-facts.json +565 -224
- package/dist/agentic/guides/module-facts.v2.json +122933 -0
- package/dist/agentic/guides/modules/ai_assistant.md +2 -2
- package/dist/agentic/guides/modules/api_docs.md +2 -2
- package/dist/agentic/guides/modules/api_keys.md +2 -2
- package/dist/agentic/guides/modules/attachments.md +2 -2
- package/dist/agentic/guides/modules/audit_logs.md +2 -2
- package/dist/agentic/guides/modules/auth.md +2 -2
- package/dist/agentic/guides/modules/business_rules.md +2 -2
- package/dist/agentic/guides/modules/catalog.md +11 -4
- package/dist/agentic/guides/modules/channel_gmail.md +2 -2
- package/dist/agentic/guides/modules/channel_imap.md +2 -2
- package/dist/agentic/guides/modules/checkout.md +8 -2
- package/dist/agentic/guides/modules/communication_channels.md +6 -6
- package/dist/agentic/guides/modules/configs.md +2 -2
- package/dist/agentic/guides/modules/content.md +2 -2
- package/dist/agentic/guides/modules/currencies.md +2 -2
- package/dist/agentic/guides/modules/customer_accounts.md +2 -2
- package/dist/agentic/guides/modules/customers.md +8 -8
- package/dist/agentic/guides/modules/dashboards.md +12 -12
- package/dist/agentic/guides/modules/data_sync.md +4 -4
- package/dist/agentic/guides/modules/design_system.md +2 -2
- package/dist/agentic/guides/modules/dictionaries.md +2 -2
- package/dist/agentic/guides/modules/directory.md +2 -2
- package/dist/agentic/guides/modules/entities.md +3 -3
- package/dist/agentic/guides/modules/eudr.md +3 -3
- package/dist/agentic/guides/modules/events.md +2 -2
- package/dist/agentic/guides/modules/feature_toggles.md +2 -2
- package/dist/agentic/guides/modules/gateway_stripe.md +2 -2
- package/dist/agentic/guides/modules/generators.md +2 -2
- package/dist/agentic/guides/modules/inbox_ops.md +2 -2
- package/dist/agentic/guides/modules/integrations.md +5 -2
- package/dist/agentic/guides/modules/messages.md +2 -2
- package/dist/agentic/guides/modules/notifications.md +2 -2
- package/dist/agentic/guides/modules/onboarding.md +2 -2
- package/dist/agentic/guides/modules/payment_gateways.md +7 -3
- package/dist/agentic/guides/modules/perspectives.md +2 -2
- package/dist/agentic/guides/modules/planner.md +2 -2
- package/dist/agentic/guides/modules/portal.md +2 -2
- package/dist/agentic/guides/modules/progress.md +2 -2
- package/dist/agentic/guides/modules/query_index.md +2 -2
- package/dist/agentic/guides/modules/record_locks.md +3 -3
- package/dist/agentic/guides/modules/resources.md +2 -2
- package/dist/agentic/guides/modules/sales.md +13 -4
- package/dist/agentic/guides/modules/scheduler.md +2 -2
- package/dist/agentic/guides/modules/search.md +4 -4
- package/dist/agentic/guides/modules/security.md +3 -3
- package/dist/agentic/guides/modules/shipping_carriers.md +2 -2
- package/dist/agentic/guides/modules/sso.md +2 -2
- package/dist/agentic/guides/modules/staff.md +7 -4
- package/dist/agentic/guides/modules/storage_s3.md +2 -2
- package/dist/agentic/guides/modules/sync_akeneo.md +4 -4
- package/dist/agentic/guides/modules/sync_excel.md +2 -2
- package/dist/agentic/guides/modules/system_status_overlays.md +2 -2
- package/dist/agentic/guides/modules/translations.md +2 -2
- package/dist/agentic/guides/modules/webhooks.md +2 -2
- package/dist/agentic/guides/modules/wms.md +31 -4
- package/dist/agentic/guides/modules/workflows.md +2 -2
- package/dist/agentic/guides/reference-module-facts.json +8335 -0
- package/dist/agentic/guides/reference-modules/example.md +489 -0
- package/dist/agentic/guides/spec-delivery.md +34 -0
- package/dist/agentic/guides/testing-debugging.md +2 -1
- package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +3 -2
- package/dist/agentic/guides/upstream/manifest.json +2 -2
- package/dist/agentic/shared/AGENTS.md.template +10 -14
- package/dist/agentic/shared/ai/harness/README.md +4 -4
- package/dist/agentic/shared/ai/harness/RELEASE.md +4 -4
- package/dist/agentic/shared/ai/harness/cases.json +11350 -5088
- package/dist/agentic/shared/ai/harness/cases.schema.json +70 -7
- package/dist/agentic/shared/ai/harness/design-system-inventory.json +6697 -0
- package/dist/agentic/shared/ai/harness/fixtures/index.json +3 -1
- package/dist/agentic/shared/ai/harness/fixtures/seeds.json +4 -0
- package/dist/agentic/shared/ai/harness/knowledge-change.schema.json +228 -0
- package/dist/agentic/shared/ai/harness/release-matrix.json +9 -4
- package/dist/agentic/shared/ai/harness/result.schema.json +60 -0
- package/dist/agentic/shared/ai/harness/routing-response.schema.json +10 -0
- package/dist/agentic/shared/ai/harness/source-link-inventory.json +3231 -0
- package/dist/agentic/shared/ai/harness/validators.json +8 -4
- package/dist/agentic/shared/ai/harness/writable-ast-oracles.mjs +5 -2
- package/dist/agentic/shared/ai/harness/writable-behavior-oracles.mjs +3 -0
- package/dist/agentic/shared/ai/harness/writable-spec-oracles.mjs +879 -0
- package/dist/agentic/shared/ai/skills/om-auto-upgrade-0.6.7-to-0.7.0/SKILL.md +102 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/SKILL.md +1 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/crud-surfaces.md +15 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/frontend-and-design-system.md +6 -0
- package/dist/agentic/shared/ai/skills/om-backend-ui-design/references/page-and-navigation.md +4 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/SKILL.md +1 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/integrity-and-concurrency.md +2 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/migration-workflow.md +2 -0
- package/dist/agentic/shared/ai/skills/om-data-model-design/references/schema-design.md +3 -1
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/SKILL.md +1 -0
- package/dist/agentic/shared/ai/skills/om-eject-and-customize/references/decision-and-procedure.md +2 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/SKILL.md +2 -0
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-template.md +3 -3
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/case-workflow.md +1 -1
- package/dist/agentic/shared/ai/skills/om-evolve-harness/references/knowledge-change.md +133 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/SKILL.md +1 -0
- package/dist/agentic/shared/ai/skills/om-integration-builder/references/provider-families.md +11 -0
- package/dist/agentic/shared/ai/skills/om-judge-agent-session/references/judge-workflow.md +1 -1
- package/dist/agentic/shared/ai/skills/om-module-scaffold/SKILL.md +2 -2
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/api-and-domain.md +14 -1
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/data-and-migrations.md +2 -0
- package/dist/agentic/shared/ai/skills/om-module-scaffold/references/module-surfaces.md +19 -0
- package/dist/agentic/shared/ai/skills/om-share-this-session/scripts/prepare-share-bundle.mjs +1 -4
- package/dist/agentic/shared/ai/skills/om-system-extension/SKILL.md +1 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/references/extension-branches.md +24 -0
- package/dist/agentic/shared/ai/skills/om-system-extension/references/unified-overrides.md +3 -1
- package/dist/agentic/shared/ai/skills/om-troubleshooter/SKILL.md +1 -0
- package/dist/agentic/shared/ai/skills/om-troubleshooter/references/diagnosis-map.md +13 -0
- package/dist/agentic/shared/ai/skills/tiers.json +2 -1
- package/dist/agentic/shared/ai/specs/2026-08-06-reference-module-activation.md +248 -0
- package/dist/agentic/shared/scripts/agent-harness-tool-server.mjs +39 -2
- package/dist/agentic/shared/scripts/design-source-contract.mjs +108 -0
- package/dist/agentic/shared/scripts/evaluate-agent-harness.mjs +935 -28
- package/dist/agentic/shared/scripts/framework-context.mjs +4 -1
- package/dist/agentic/shared/scripts/run-agent-harness-release.mjs +1 -1
- package/dist/agentic/shared/scripts/validate-knowledge-change.mjs +1511 -0
- package/dist/lib/__integration__/TC-INT-008.spec.js +1 -0
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-setup.js +9 -1
- package/dist/lib/agentic-setup.js.map +2 -2
- package/dist/lib/generators/module-extension-facts.js +93 -26
- package/dist/lib/generators/module-extension-facts.js.map +3 -3
- package/dist/lib/generators/module-facts-discovery.js +23 -0
- package/dist/lib/generators/module-facts-discovery.js.map +2 -2
- package/dist/lib/generators/module-facts.js +969 -41
- package/dist/lib/generators/module-facts.js.map +2 -2
- package/dist/lib/generators/module-override-targets.js +35 -11
- package/dist/lib/generators/module-override-targets.js.map +2 -2
- package/dist/lib/generators/module-registry.js +105 -2
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/resolver.js +5 -0
- package/dist/lib/resolver.js.map +2 -2
- package/dist/lib/testing/integration-discovery.js +34 -0
- package/dist/lib/testing/integration-discovery.js.map +2 -2
- package/dist/lib/testing/integration.js +0 -2
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +4 -4
- package/dist/mercato.js.map +2 -2
- package/package.json +6 -6
- package/src/lib/__integration__/TC-INT-008.spec.ts +4 -2
- package/src/lib/__tests__/resolve-environment.test.ts +18 -0
- package/src/lib/agentic-setup.ts +10 -2
- package/src/lib/generators/__tests__/helpers/override-target-diagnostic-fixtures.ts +150 -0
- package/src/lib/generators/__tests__/module-extension-facts.test.ts +290 -0
- package/src/lib/generators/__tests__/module-facts.bc-guard.test.ts +72 -7
- package/src/lib/generators/__tests__/module-facts.computed-di-token.test.ts +88 -0
- package/src/lib/generators/__tests__/module-facts.example-fact-coverage.test.ts +502 -0
- package/src/lib/generators/__tests__/module-facts.local-reference.test.ts +414 -0
- package/src/lib/generators/__tests__/module-facts.search-entity-id.test.ts +151 -0
- package/src/lib/generators/__tests__/module-facts.source-links.test.ts +42 -1
- package/src/lib/generators/__tests__/module-override-targets.diagnostic-wiring.test.ts +92 -0
- package/src/lib/generators/__tests__/module-override-targets.test.ts +24 -0
- package/src/lib/generators/__tests__/module-override-targets.unknown-mode.test.ts +117 -0
- package/src/lib/generators/__tests__/module-subset.test.ts +60 -0
- package/src/lib/generators/module-extension-facts.ts +181 -25
- package/src/lib/generators/module-facts-discovery.ts +46 -0
- package/src/lib/generators/module-facts.ts +1330 -86
- package/src/lib/generators/module-override-targets.ts +70 -26
- package/src/lib/generators/module-registry.ts +135 -2
- package/src/lib/resolver.ts +6 -1
- package/src/lib/testing/__tests__/integration-discovery.test.ts +35 -0
- package/src/lib/testing/integration-discovery.ts +50 -0
- package/src/lib/testing/integration.ts +0 -2
- package/src/mercato.ts +3 -3
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { collectModuleOverrideTargets } from '../module-override-targets'
|
|
2
|
+
import {
|
|
3
|
+
FIXTURE_MODULE_ID,
|
|
4
|
+
FIXTURE_SOURCE_ROOT,
|
|
5
|
+
OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES,
|
|
6
|
+
catalogWith,
|
|
7
|
+
catalogWithout,
|
|
8
|
+
collectWithCatalogOperations,
|
|
9
|
+
fixtureFacts,
|
|
10
|
+
realCatalogOperations,
|
|
11
|
+
} from './helpers/override-target-diagnostic-fixtures'
|
|
12
|
+
|
|
13
|
+
function codesFor(
|
|
14
|
+
diagnostics: { code: string; domain: string }[],
|
|
15
|
+
domain: string,
|
|
16
|
+
): string[] {
|
|
17
|
+
return diagnostics.filter((diagnostic) => diagnostic.domain === domain).map((diagnostic) => diagnostic.code)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('override-target diagnostic wiring — the published code names the real cause', () => {
|
|
21
|
+
it('publishes unknown-framework-mode when the catalog describes the host with an unusable operation', () => {
|
|
22
|
+
const { overrideTargets, overrideTargetDiagnostics } = collectWithCatalogOperations(
|
|
23
|
+
catalogWith('cli', 'merge-deep'),
|
|
24
|
+
fixtureFacts(),
|
|
25
|
+
)
|
|
26
|
+
const cliDiagnostics = overrideTargetDiagnostics.filter((diagnostic) => diagnostic.domain === 'cli')
|
|
27
|
+
expect(cliDiagnostics.map((diagnostic) => diagnostic.code)).toEqual(['unknown-framework-mode'])
|
|
28
|
+
expect(cliDiagnostics[0]).toEqual({
|
|
29
|
+
code: 'unknown-framework-mode',
|
|
30
|
+
moduleId: FIXTURE_MODULE_ID,
|
|
31
|
+
domain: 'cli',
|
|
32
|
+
candidatePath: ['cli', 'fixture:seed'],
|
|
33
|
+
source: { sourcePath: `${FIXTURE_SOURCE_ROOT}/cli.ts` },
|
|
34
|
+
})
|
|
35
|
+
expect(overrideTargets.some((target) => target.domain === 'cli')).toBe(false)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('publishes unknown-framework-domain when the catalog does not describe the host at all', () => {
|
|
39
|
+
const { overrideTargets, overrideTargetDiagnostics } = collectWithCatalogOperations(
|
|
40
|
+
catalogWithout('cli'),
|
|
41
|
+
fixtureFacts(),
|
|
42
|
+
)
|
|
43
|
+
expect(codesFor(overrideTargetDiagnostics, 'cli')).toEqual(['unknown-framework-domain'])
|
|
44
|
+
expect(overrideTargets.some((target) => target.domain === 'cli')).toBe(false)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('never collapses the two causes: one run emits a distinct code per failing domain', () => {
|
|
48
|
+
const operations = catalogWithout('cli')
|
|
49
|
+
operations.workers = 'merge-deep'
|
|
50
|
+
const { overrideTargetDiagnostics } = collectWithCatalogOperations(
|
|
51
|
+
operations,
|
|
52
|
+
fixtureFacts({
|
|
53
|
+
ownedContracts: {
|
|
54
|
+
worker: [
|
|
55
|
+
{
|
|
56
|
+
kind: 'worker',
|
|
57
|
+
id: 'fixture.worker',
|
|
58
|
+
source: { sourcePath: `${FIXTURE_SOURCE_ROOT}/workers/fixture.ts`, line: 1 },
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
)
|
|
64
|
+
expect(codesFor(overrideTargetDiagnostics, 'cli')).toEqual(['unknown-framework-domain'])
|
|
65
|
+
expect(codesFor(overrideTargetDiagnostics, 'workers')).toEqual(['unknown-framework-mode'])
|
|
66
|
+
expect(new Set(overrideTargetDiagnostics.map((diagnostic) => diagnostic.code)).size).toBe(2)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('emits the target and no diagnostic when the real catalog describes the host', () => {
|
|
70
|
+
const stubbed = collectWithCatalogOperations(realCatalogOperations(), fixtureFacts())
|
|
71
|
+
const direct = collectModuleOverrideTargets(fixtureFacts())
|
|
72
|
+
expect(stubbed).toEqual(direct)
|
|
73
|
+
expect(direct.overrideTargetDiagnostics).toEqual([])
|
|
74
|
+
expect(direct.overrideTargets.map((target) => target.path)).toEqual([['cli', 'fixture:seed']])
|
|
75
|
+
expect(direct.overrideTargets[0].modes).toEqual(['disable-replace'])
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
describe('every negative-fixture diagnostic code is produced by a real fixture', () => {
|
|
80
|
+
it.each(OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES.map((fixture) => [fixture.code, fixture] as const))(
|
|
81
|
+
'%s',
|
|
82
|
+
(code, fixture) => {
|
|
83
|
+
const diagnostics = fixture.run()
|
|
84
|
+
expect(diagnostics.map((diagnostic) => diagnostic.code)).toContain(code)
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
it('covers each code with exactly one fixture', () => {
|
|
89
|
+
const codes = OVERRIDE_TARGET_DIAGNOSTIC_FIXTURES.map((fixture) => fixture.code)
|
|
90
|
+
expect(new Set(codes).size).toBe(codes.length)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
@@ -222,6 +222,30 @@ describe('module override targets — deterministic diagnostics (never a guessed
|
|
|
222
222
|
expect(diag?.source).toBeUndefined()
|
|
223
223
|
})
|
|
224
224
|
|
|
225
|
+
it('never guesses a mode: the framework catalog describes every adapter host', () => {
|
|
226
|
+
const { overrideTargets, overrideTargetDiagnostics } = collectModuleOverrideTargets(baseFacts())
|
|
227
|
+
expect(overrideTargetDiagnostics.filter((diagnostic) => diagnostic.code === 'unknown-framework-domain')).toEqual([])
|
|
228
|
+
expect(overrideTargets.length).toBeGreaterThan(0)
|
|
229
|
+
for (const target of overrideTargets) {
|
|
230
|
+
expect(target.modes).toHaveLength(1)
|
|
231
|
+
expect(['disable-replace', 'replace', 'additive']).toContain(target.modes[0])
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
it('routes every widget contribution by its own kind/payload discriminant', () => {
|
|
236
|
+
const { overrideTargets } = collectModuleOverrideTargets(baseFacts())
|
|
237
|
+
const widgets = overrideTargets
|
|
238
|
+
.filter((target) => target.domain === 'widgets')
|
|
239
|
+
.map((target) => `${target.path.slice(0, 2).join('/')} ${target.key}`)
|
|
240
|
+
.sort()
|
|
241
|
+
expect(widgets).toEqual([
|
|
242
|
+
'widgets/components section:demo.login',
|
|
243
|
+
'widgets/dashboard demo.card',
|
|
244
|
+
'widgets/injection demo.table-widget',
|
|
245
|
+
'widgets/injection demo.widget',
|
|
246
|
+
])
|
|
247
|
+
})
|
|
248
|
+
|
|
225
249
|
it('emits missing-source when an acl feature has no indexed provenance', () => {
|
|
226
250
|
const facts = baseFacts({ factSources: [] })
|
|
227
251
|
const { overrideTargets, overrideTargetDiagnostics } = collectModuleOverrideTargets(facts)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { ModuleExtensionHostFact } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
2
|
+
import { getFrameworkOverrideHostOperations, getFrameworkOverrideModes } from '../module-extension-facts'
|
|
3
|
+
import {
|
|
4
|
+
MODULE_OVERRIDE_MODES,
|
|
5
|
+
MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES,
|
|
6
|
+
resolveFrameworkOverrideModes,
|
|
7
|
+
} from '../module-override-targets'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A catalog host declaring an operation this generator does not know. Every real
|
|
11
|
+
* catalog host declares a valid mode today, so a stub is the only way to observe
|
|
12
|
+
* what the raw operation map does with one — which is the whole point of the map
|
|
13
|
+
* existing beside the validated mode map.
|
|
14
|
+
*/
|
|
15
|
+
const CATALOG_HOST_WITH_UNRECOGNIZED_OPERATION: ModuleExtensionHostFact = {
|
|
16
|
+
key: 'framework.module-override.fixture.aheadOfGenerator',
|
|
17
|
+
id: 'module-override:fixture.aheadOfGenerator',
|
|
18
|
+
resolution: 'framework',
|
|
19
|
+
family: 'module-override',
|
|
20
|
+
ownerModule: 'framework',
|
|
21
|
+
capabilities: ['module-override'],
|
|
22
|
+
operations: ['merge-deep'],
|
|
23
|
+
bound: true,
|
|
24
|
+
stability: 'stable',
|
|
25
|
+
source: {
|
|
26
|
+
kind: 'framework',
|
|
27
|
+
path: 'packages/shared/src/modules/overrides.ts',
|
|
28
|
+
symbol: 'ModuleOverrides.fixture.aheadOfGenerator',
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('unknown-framework-mode override-target diagnostic', () => {
|
|
33
|
+
it('is part of the closed diagnostic-code set', () => {
|
|
34
|
+
expect([...MODULE_OVERRIDE_TARGET_DIAGNOSTIC_CODES]).toEqual([
|
|
35
|
+
'missing-owned-fact',
|
|
36
|
+
'missing-source',
|
|
37
|
+
'unsupported-dynamic-key',
|
|
38
|
+
'unknown-framework-domain',
|
|
39
|
+
'unknown-framework-mode',
|
|
40
|
+
])
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('distinguishes an absent catalog host from a host whose declared mode is unrecognized', () => {
|
|
44
|
+
expect(resolveFrameworkOverrideModes(undefined)).toEqual({ outcome: 'unknown-framework-domain' })
|
|
45
|
+
expect(resolveFrameworkOverrideModes('merge-deep')).toEqual({
|
|
46
|
+
outcome: 'unknown-framework-mode',
|
|
47
|
+
operation: 'merge-deep',
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('resolves every public mode and nothing else', () => {
|
|
52
|
+
for (const mode of MODULE_OVERRIDE_MODES) {
|
|
53
|
+
expect(resolveFrameworkOverrideModes(mode)).toEqual({ outcome: 'resolved', modes: [mode] })
|
|
54
|
+
}
|
|
55
|
+
expect(resolveFrameworkOverrideModes('')).toEqual({ outcome: 'unknown-framework-mode', operation: '' })
|
|
56
|
+
expect(resolveFrameworkOverrideModes('DISABLE-REPLACE')).toEqual({
|
|
57
|
+
outcome: 'unknown-framework-mode',
|
|
58
|
+
operation: 'DISABLE-REPLACE',
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('never guesses a target: an unrecognized mode yields no modes at all', () => {
|
|
63
|
+
const resolution = resolveFrameworkOverrideModes('replace-all')
|
|
64
|
+
expect(resolution.outcome).toBe('unknown-framework-mode')
|
|
65
|
+
expect('modes' in resolution).toBe(false)
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
describe('framework override host operations', () => {
|
|
70
|
+
const operations = getFrameworkOverrideHostOperations()
|
|
71
|
+
|
|
72
|
+
it('exposes the raw declared operation for every catalog host, unfiltered', () => {
|
|
73
|
+
expect(Object.keys(operations).length).toBeGreaterThan(0)
|
|
74
|
+
expect(operations['routes.api']).toBe('disable-replace')
|
|
75
|
+
expect(operations['setup']).toBe('replace')
|
|
76
|
+
expect(operations['ai.extensions']).toBe('additive')
|
|
77
|
+
expect(operations['nav.groupOrder']).toBe('additive')
|
|
78
|
+
expect(operations['no.such.host']).toBeUndefined()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('keeps the validated mode map a strict subset of the raw operations', () => {
|
|
82
|
+
const modes = getFrameworkOverrideModes()
|
|
83
|
+
for (const [host, mode] of Object.entries(modes)) {
|
|
84
|
+
expect(operations[host]).toBe(mode)
|
|
85
|
+
expect(MODULE_OVERRIDE_MODES).toContain(mode)
|
|
86
|
+
}
|
|
87
|
+
for (const [host, operation] of Object.entries(operations)) {
|
|
88
|
+
const resolution = resolveFrameworkOverrideModes(operation)
|
|
89
|
+
expect(resolution.outcome === 'resolved').toBe(host in modes)
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('a catalog operation the generator does not recognize', () => {
|
|
95
|
+
const hosts = [CATALOG_HOST_WITH_UNRECOGNIZED_OPERATION]
|
|
96
|
+
const dottedHost = 'fixture.aheadOfGenerator'
|
|
97
|
+
|
|
98
|
+
it('survives the raw operation map unfiltered', () => {
|
|
99
|
+
expect(getFrameworkOverrideHostOperations(hosts)).toEqual({ [dottedHost]: 'merge-deep' })
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('is dropped from the validated mode map, which is exactly why the raw map must not filter', () => {
|
|
103
|
+
expect(getFrameworkOverrideModes(hosts)).toEqual({})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('reads as a catalog this generator has fallen behind, never as a host that does not exist', () => {
|
|
107
|
+
const rawOperations = getFrameworkOverrideHostOperations(hosts)
|
|
108
|
+
const filteredOperations = getFrameworkOverrideModes(hosts)
|
|
109
|
+
expect(resolveFrameworkOverrideModes(rawOperations[dottedHost])).toEqual({
|
|
110
|
+
outcome: 'unknown-framework-mode',
|
|
111
|
+
operation: 'merge-deep',
|
|
112
|
+
})
|
|
113
|
+
expect(resolveFrameworkOverrideModes(filteredOperations[dottedHost])).toEqual({
|
|
114
|
+
outcome: 'unknown-framework-domain',
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
})
|
|
@@ -1908,6 +1908,66 @@ describe('all generated files are valid with varying subsets', () => {
|
|
|
1908
1908
|
expect(sudoTargets).toContain('sudoTargets')
|
|
1909
1909
|
})
|
|
1910
1910
|
|
|
1911
|
+
it('rejects generator plugins that declare the same output file', async () => {
|
|
1912
|
+
scaffoldModule(tmpDir, 'security_ext', 'pkg', ['security.mfa-providers.ts'])
|
|
1913
|
+
touchFile(
|
|
1914
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'security_ext', 'generators.ts'),
|
|
1915
|
+
SECURITY_GENERATORS_CONTENT.replace(
|
|
1916
|
+
"outputFileName: 'security-sudo.generated.ts'",
|
|
1917
|
+
"outputFileName: 'security-mfa-providers.generated.ts'",
|
|
1918
|
+
),
|
|
1919
|
+
)
|
|
1920
|
+
const resolver = createMockResolver(tmpDir, [
|
|
1921
|
+
{ id: 'security_ext', from: '@open-mercato/core' },
|
|
1922
|
+
])
|
|
1923
|
+
|
|
1924
|
+
await expect(generateModuleRegistry({ resolver, quiet: true })).rejects.toThrow(
|
|
1925
|
+
"declare the same output file 'security-mfa-providers.generated.ts'",
|
|
1926
|
+
)
|
|
1927
|
+
})
|
|
1928
|
+
|
|
1929
|
+
it('rejects runtime imports in generators.ts before loading the plugin', async () => {
|
|
1930
|
+
scaffoldModule(tmpDir, 'security_ext', 'pkg', ['security.mfa-providers.ts'])
|
|
1931
|
+
touchFile(
|
|
1932
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'security_ext', 'generators.ts'),
|
|
1933
|
+
`import { randomUUID } from 'node:crypto'\n${SECURITY_GENERATORS_CONTENT}`,
|
|
1934
|
+
)
|
|
1935
|
+
const resolver = createMockResolver(tmpDir, [
|
|
1936
|
+
{ id: 'security_ext', from: '@open-mercato/core' },
|
|
1937
|
+
])
|
|
1938
|
+
|
|
1939
|
+
await expect(generateModuleRegistry({ resolver, quiet: true })).rejects.toThrow(
|
|
1940
|
+
'generators.ts may use only `import type`',
|
|
1941
|
+
)
|
|
1942
|
+
})
|
|
1943
|
+
|
|
1944
|
+
it('repairs stale plugin output and removes it when the declaring module is disabled', async () => {
|
|
1945
|
+
scaffoldModule(tmpDir, 'security_ext', 'pkg', ['security.mfa-providers.ts'])
|
|
1946
|
+
touchFile(
|
|
1947
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'security_ext', 'generators.ts'),
|
|
1948
|
+
SECURITY_GENERATORS_CONTENT,
|
|
1949
|
+
)
|
|
1950
|
+
const activeResolver = createMockResolver(tmpDir, [
|
|
1951
|
+
{ id: 'security_ext', from: '@open-mercato/core' },
|
|
1952
|
+
])
|
|
1953
|
+
await generateModuleRegistry({ resolver: activeResolver, quiet: true })
|
|
1954
|
+
|
|
1955
|
+
const outputPath = path.join(tmpDir, 'output', 'generated', 'security-mfa-providers.generated.ts')
|
|
1956
|
+
const checksumPath = path.join(tmpDir, 'output', 'generated', 'security-mfa-providers.generated.checksum')
|
|
1957
|
+
const manifestPath = path.join(tmpDir, 'output', 'generated', '.generator-plugin-outputs.json')
|
|
1958
|
+
const expected = fs.readFileSync(outputPath, 'utf8')
|
|
1959
|
+
fs.writeFileSync(outputPath, 'stale output\n')
|
|
1960
|
+
|
|
1961
|
+
await generateModuleRegistry({ resolver: activeResolver, quiet: true })
|
|
1962
|
+
expect(fs.readFileSync(outputPath, 'utf8')).toBe(expected)
|
|
1963
|
+
|
|
1964
|
+
const disabledResolver = createMockResolver(tmpDir, [])
|
|
1965
|
+
await generateModuleRegistry({ resolver: disabledResolver, quiet: true })
|
|
1966
|
+
expect(fs.existsSync(outputPath)).toBe(false)
|
|
1967
|
+
expect(fs.existsSync(checksumPath)).toBe(false)
|
|
1968
|
+
expect(fs.existsSync(manifestPath)).toBe(false)
|
|
1969
|
+
})
|
|
1970
|
+
|
|
1911
1971
|
it('notifications.generated.ts uses typed fallback for legacy "types" export', async () => {
|
|
1912
1972
|
scaffoldModule(tmpDir, 'notif_mod', 'pkg', ['notifications.ts'])
|
|
1913
1973
|
const resolver = createMockResolver(tmpDir, [
|